Не виртуальный деструктор в базовом классе, но виртуальный деструктор в производном классе вызывает ошибку сегментации

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

Я написал небольшой тест, чтобы подтвердить свой ответ, но нашел что-то интересное. Очевидно, что если вы создаете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;, Кто-нибудь может сказать мне, почему это так?

Ответы на вопрос(2)

Ваш ответ на вопрос