уничтожение динамически выделяемой памяти (объекта массива) в C ++ - PullRequest
0 голосов
/ 25 сентября 2018

ниже вы найдете код (который компилируется / запускается), который вкратце вызывает функцию, которая динамически распределяет массив в куче.

#include "stdafx.h"

#include <stdio.h>

class A
{

    public:

    A()
    {
        printf ( "constructor has been called !!! \n" );
    }

    ~A()
    {
        printf ( "destructor has been called !!! \n" );
    }

    char* f( void )
    {

        //char *data_raw = NULL;

        data_raw = NULL;

        data_raw = new char [ 20 ];

        for( int i = 0; i < 20; i++ )
        {
            data_raw[ i ] = '0';    
        }

        data_raw[  0 ] = 'h';
        data_raw[  1 ] = 'e';
        data_raw[  2 ] = 'l';
        data_raw[  3 ] = 'l';
        data_raw[  4 ] = 'o';
        data_raw[  5 ] = ' ';
        data_raw[  6 ] = 'w';
        data_raw[  7 ] = 'o';
        data_raw[  8 ] = 'r';
        data_raw[  9 ] = 'l';
        data_raw[ 10 ] = 'd';
        data_raw[ 11 ] = '!';

        return data_raw;

    } //data raw ptr-var is destroyed

    private:

        char *data_raw;

};


int  _tmain( int argc, _TCHAR* argv[] )
{

    char *data = NULL;

    printf( "data: %c", data );

    A a;

    data = a.f();

    delete [] data;  

    return 0;

}

Мои вопросы:

1) относительно уничтожения памяти, выделенной динамически, я должен использовать delete или delete []?они оба компилируются ...

2) когда я использую первый (удалить), вызывается деструктор класса, но не когда я использую delete []?

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

вы вызываете delete[], когда инициализируете массив в куче с помощью new и используете delete при инициализации объекта в куче с помощью new.

в примечании,предложил бы удалить членов класса его владельцем.Вы будете требовать много хлопот, если будете делать то, что делаете здесь.удаляя массив за пределами A.

для этого примера, ничто не мешает вам вызвать delete[] data_raw в деструкторе класса A. Нет необходимости принимать его извне A или даже возвращать aуказатель на массив.

class A
{
public:
   A()
  {
    printf ( "constructor has been called !!! \n" );
    data_raw = NULL;
    data_raw = new char [ 20 ];
    //....rest ofthe code from f( void )
    //....no need to return data_raw        
  }

  ~A()
  {
    printf ( "destructor has been called !!! \n" );
    delete [] data_raw; 
  }

private:
  char *data_raw;
};
0 голосов
/ 25 сентября 2018

Вы должны просто никогда использовать класс, такой как А., особенно не так, как вы его используете.

В частности:

  • Вы не должны передаватьвладение памятью при сохранении указателя на принадлежащий объект (если это не слабая ссылка).Это почти всегда означает, что вы делаете неверное предположение о том, что указатель действителен, несмотря на тот факт, что память могла легко быть освобождена задолго до того, как был использован не принадлежащий указателю.
  • Вы не должны непосредственно выделять иосвободить память за исключением особых случаев.Используйте существующие классы контейнеров или, если они не подходят, используйте умные указатели - std::unique_ptr, std::shared_ptr и std::weak_ptr - в зависимости от ситуации.
  • Вы не должны передавать указатели на выделенныепамять, в которой выделенная сумма (или нижняя граница выделенной суммы) неизвестна новому владельцу.Либо передайте ссылки на соответствующие объекты, либо передайте контейнеры, используя семантику перемещения, , либо передайте , охватывающий .Обратите внимание, что это может произойти, когда вы просто просто передаете значения (из-за copy ellisions ).
  • Обычно вы предпочитаете сохранять владение памятью с объектом создателя, что позволяет не иметь доступаи позволяя объекту-создателю уничтожить то, что он создал.

Ваш код не следует ни одному из этих правил!Это страшно и опасно!

Я бы переписал ваш код, чтобы следовать вашим рекомендациям, но, поскольку непонятно, зачем вам нужен метод f или класс A, я бы просто выбрал:

#include <iostream>
#include <string>

std::string A_f() { return "hello world"; }

int main( int argc, const char* argv[] )
{
    std::cout << A_f();
}

или просто

#include <iostream>

int main( int argc, const char* argv[] )
{
    std::cout << "hello world";
}
...