Не виртуальный деструктор в базовом классе, но виртуальный деструктор в производном классе вызывает ошибку сегментации
Недавно на собеседовании меня спросили о проблеме утечки памяти в производных классах, когда деструктор базового класса не объявлен виртуальным.
Я написал небольшой тест, чтобы подтвердить свой ответ, но нашел что-то интересное. Очевидно, что если вы создаетеDerived
объект черезnew
но храните его указатель какBase*
деструктор производного объекта не будет вызван, если указатель будет удален (так много для моего ответа на вопрос).
Я подумал, является ли деструктор производного класса виртуальным или нет, в этом случае не имеет значения, но в моей системе следующий код показывает иначе:
#include <iostream>
#include <string>
// just a helper class, printing its name out when it is destructed
class PrintOnDestruct
{
public:
PrintOnDestruct( const std::string& name )
: name_( name )
{}
~PrintOnDestruct()
{
std::cout << "Destructing: " << name_ << std::endl;
}
protected:
std::string name_;
};
// the Base class
class Base
{
public:
Base()
{
print_on_destruct_ = new PrintOnDestruct( "Base" );
}
// the destructor is NOT virtual!
~Base()
{
delete print_on_destruct_;
}
protected:
PrintOnDestruct* print_on_destruct_;
};
// the NonVirtualDerived class, doesn't have a virtual destructor either
class NonVirtualDerived : public Base
{
public:
NonVirtualDerived()
: Base()
{
print_on_destruct_child_ = new PrintOnDestruct( "NonVirtualDerived" );
}
// the destructor is NOT virtual!
~NonVirtualDerived()
{
delete print_on_destruct_child_;
}
protected:
PrintOnDestruct* print_on_destruct_child_;
};
// the VirtualDerived class does have a virtual destructor
class VirtualDerived : public Base
{
public:
VirtualDerived()
: Base()
{
print_on_destruct_child_ = new PrintOnDestruct( "VirtualDerived" );
}
// the destructor is virtual!
virtual ~VirtualDerived()
{
delete print_on_destruct_child_;
}
protected:
PrintOnDestruct* print_on_destruct_child_;
};
int main()
{
// create the two child classes
Base* non_virtual_derived = new NonVirtualDerived;
Base* virtual_derived = new VirtualDerived;
// delete the two objects
delete non_virtual_derived; // works as expected (only calls Base's destructor, the memory of NonVirtualDerived will be leaked)
delete virtual_derived; // segfault, after calling Base's destructor
return 0;
}
Я ожидал, что программа выведет следующие две строки и выйдет нормально:
Destructing: Base
Destructing: Base
Я получаю этот вывод, но сразу после второй строки программа завершает работу с ошибкой сегментации. И сообщение:
*** Error in `...': free(): invalid pointer: 0x00000000006020e8 ***
Я изменил порядок двух звонков наdelete
, но программа всегда будет segfault в вызовеdelete virtual_derived;
, Кто-нибудь может сказать мне, почему это так?