2015-02-26 4 views
0
class ParentClass { 
protected: 
    int* intArray; 

public: 
    ~ParentClass(){ 
     delete [] intArray; 
    } 
}; 

class ChildClass : public ParentClass { 
public: 
    ChildClass() : ParentClass() { 
     intArray = new int[5]; 
    } 
}; 

int main(int argc, const char * argv[]) { 
    ChildClass child; 
    child.~ChildClass(); //This line crashes the program. why?? 
} 

Специфическая ошибка, которую он выдает: инициализации (37640,0x7fff78623300) таНос: * ошибка для объекта 0x100100aa0: указатель освобождения не было выделено * установить контрольную точку в malloc_error_break для отладкиПочему вызов деструктора класса Base приводит к сбою этой программы?

указатель ссылается на intArray, объявленный в ParentClass, ошибка указывает, что память не была выделена, но она была назначена в конструкторе ChildClass.

Может кто-нибудь объяснить, в каком процессе это происходит, чтобы сгенерировать эту ошибку?

+1

Вы уверены, что это * это * строка, а не переменная 'child', выходящая из области видимости и имеющая свой деструктор, называемый * снова *? –

+0

Означает ли указанная строка аварийное завершение программы, или существование линии приводит к сбою программы позже? –

+1

wot r u doing m8 –

ответ

2

Проблема не в том, что intArray не выделяется, это значит, что вы освобождаете его дважды.

ChildClass child; создает экземпляр ChildClass и вызывает конструктор по умолчанию, который выделяет intArray в порядке, без проблем.

Затем ваш код явно вызывает деструктор (что вам вообще не нужно делать для выделенных стеком/автоматических объектов).

Затем компилятор вставляет другой вызов деструктору во время очистки области, что приводит к тому, что delete[] будет вызываться второй раз, что является неправильным и вызывает сбой. Ваш отладчик, вероятно, сообщает о последней строке функции (где ваш явный вызов деструктора), когда она действительно должна указывать на закрывающую фигуру.

Конечно, установите контрольную точку в своем деструкторе и запустите свою программу и посмотрите, сколько раз она попала.

+0

Компилятор _could_ должен перемещать автоматическое уничтожение 'child' точно там, откуда его сообщают, так как' child' никогда фактически не используется в действительности в этой программе. –

+0

Спасибо за четкий ответ. Точка разлома очистила все! – Weathered

0

child является местным объектом main(). Он автоматически уничтожается при выходе из функции.

К сожалению, вы вручную уничтожили его перед тем, как покинуть функцию, вызвав явно деструктор. Таким образом, он уничтожил два раза (один слишком много): второй раз он падает!

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

Явный вызов деструктора применим только в очень редком случае: если вы хотите повторно использовать хранилище динамического объекта с размещением -.

Примечание: в ParentClass вы должны инициализировать intArray в nullptr. Это позволит убедиться, что если случайно не будет выделено выделение, delete не будет пытаться освободить унитализированный указатель.

1

Вы испытываете неопределенное поведение. Из стандарта C++:

Как только деструктор вызывается для объекта, объект больше не существует; поведение не определено, если деструктор вызывается для объекта, срок службы которого закончился (3.8).[Пример: если деструктор для автоматического объекта явно вызывается, а затем блок оставлен таким образом, что обычно вызывает неявное разрушение объекта, поведение не определено.

Смежные вопросы