Деструктор не вызывается при выходе из области видимости - PullRequest
2 голосов
/ 18 июля 2011

Я изучаю управление памятью на C ++ и не понимаю, почему при выходе из области вызываются только некоторые деструкторы.В приведенном ниже коде только деструктор obj1 вызывается, когда myfunc заканчивается, а не для динамически размещенного obj2.

int myfunc (cl1 *oarg) {

    cout << "myfunc called" << std::endl;
    cl1 obj1(222,"NY");
    cl1 *obj2;
    obj2= new cl1;
    oarg->disp();
    obj2 -> ~cl1 ;

}

Вот деструктор, который у меня есть:

cl1 :: ~cl1 () {

std::cout<< " cl1 destructor called"<<std::endl;
std::cout << this->data << std::endl; //just to identify the obj
delete [] str;
str = NULL ;

};

Ответы [ 8 ]

6 голосов
/ 18 июля 2011

Если вы выделите объект, используя new

obj2= new cl1;

Тогда, если вы не вызовете delete, его деструктор не будет вызываться неявно.Дэвид, смыслы в комментариях. Можно явно вызывать деструктор объекта, но по моему опыту редко возникает необходимость вручную вызывать деструктор, если только не используется размещение новой версии новой.вверх (вызывая их деструкторы), когда их область действия заканчивается.

Динамически размещенные объекты не очищаются неявно, пользователь несет ответственность за их очистку, явно вызывая delete.

Именно по этой причине не следует использовать необработанные указатели, а использовать умные указатели.

2 голосов
/ 18 июля 2011

obj1 - это объект типа cl1 с длительностью автоматического хранения (он размещается в стеке, а его время жизни определяется областью, в которой он находится)

obj1 - это объект типа cl1*. То есть это указатель . Указатель также имеет автоматическую продолжительность хранения, но объект, на который он указывает, не имеет. Он указывает на динамически размещаемый объект в бесплатном хранилище.

При выходе из области действия объекты с автоматическим хранением уничтожаются. obj1 уничтожается, вызывая вашего деструктора. И obj2 также уничтожается, но obj2 не относится к типу cl1, поэтому он не вызывает деструктор cl1. Это указатель, и он не делает ничего особенного, когда уничтожается.

Указатели не владеют объектами, на которые они указывают, и поэтому они ничего не делают, чтобы гарантировать, что указанный объект будет уничтожен или очищен. (Если вам нужен «владеющий» указатель, для этого нужны классы умных указателей)

Учтите, что вы можете легко иметь несколько указателей, указывающих на один и тот же объект.

Если указатель автоматически удалит объект, на который он указывает, это приведет к ошибкам. Объект, на который указывают два разных указателя, будет удален дважды.

2 голосов
/ 18 июля 2011

Динамически размещенные объекты ваша ответственность - вам нужно явно очистить их. Автоматические объекты (такие как obj1) очищаются при выходе из области действия, автоматически . В этом случае до выхода из области действия явно вызовите delete obj2. ПРИМЕЧАНИЕ: эта строка obj2 -> ~cl1 - ничего не делает - delete позаботится о правильном запуске деструктора.

1 голос
/ 18 июля 2011

Деструкторы вызываются автоматически, когда объект, созданный в стеке, выходит из области видимости.

Для динамически размещаемых объектов вам необходимо вызвать delete obj.Удалить автоматически вызовет ваш деструктор для вас.

1 голос
/ 18 июля 2011

obj2 -> ~cl1 ;

Не делай этого!Вместо этого используйте delete obj2;.

Приложение
То, что вы пытались сделать, - это явно вызвать деструктор.Ваш код этого не делает.Ваш код получает адрес деструктора и затем помещает его в корзину битов.Ваш код не работает.Правильный способ явного вызова деструктора: obj2->~cli();.

Явный вызов деструктора - это обычно то, что вы не должны делать.

Что вы должны сделать, это удалить память, созданную new.Правильный способ сделать это - использовать оператор delete.Это автоматически вызывает деструктор и освобождает память.Деструктор не освобождает память.Неиспользование удаления приводит к утечке памяти.

0 голосов
/ 21 февраля 2013

Используйте std :: unique_ptr или std :: shared_ptr вместо необработанного указателя. Это лучший способ избежать утечки памяти или двойного освобождения.

Это правильный путь в современном C ++.

int myfunc (cl1 *oarg) 
{
    cout << "myfunc called" << std::endl;
    cl1 obj1(222,"NY");
    std::unique_ptr<cl1> obj2( new cl1 );
    oarg->disp();
}
0 голосов
/ 18 июля 2011

Прежде всего вы должны использовать оператор delete, чтобы уничтожить объект, а не вызывать его деструктор напрямую.Во-вторых, делая new, вы сообщаете компилятору, что не хотите удалить объект, когда он выходит из области видимости.В таком случае вам необходимо явно delete objj2; удалить объект.

0 голосов
/ 18 июля 2011

Вы должны использовать delete для динамически размещаемых объектов:

delete obj2;

, это вызывает деструктор и освобождает память.Вам будет гораздо лучше использовать умные указатели для управления такими объектами - они будут вызывать delete для вас даже в случае исключения между new и delete.

...