Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non virtual destructor in base class, but virtual destructor in derived class cause segmentation fault

recently in a job interview I was asked about the problem of leaking memory in derived classes when the base class's destructor is not declared virtual.

I wrote a small test to confirm my answer, but I found something interesting. Obviously, if you create a Derived object via new but store its pointer as a Base*, the derived object's destructor won't be called, if the pointer is deleted (so much for my answer to the question).

I thought whether the derived class's destructor is virtual or not is irelevant in that case, but on my system the following code shows otherwise:

#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;
}

I would have expected the program to output the following two lines and quit normally:

Destructing: Base
Destructing: Base

I get that output, but immediately after the second line the program quits with a segmentation fault. And the message:

*** Error in `...': free(): invalid pointer: 0x00000000006020e8 ***

I've changed the order of the two calls to delete, but the programm would always segfault in the call to delete virtual_derived;. Can anybody tell me why this is so?

like image 573
Sebastian Schneider Avatar asked Oct 23 '13 12:10

Sebastian Schneider


People also ask

What happens if base class destructor is not virtual?

Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results in undefined behavior.

Does derived class destructor need to be virtual?

If you want to call a derived class function when all you have is a base class pointer/reference, that function must be declared virtual .

Does a derived class need a destructor?

No. You never need to explicitly call a destructor (except with placement new). A derived class's destructor (whether or not you explicitly define one) automagically invokes the destructors for base class subobjects. Base classes are destructed after member objects.

Why does base class need virtual destructor?

Virtual destructors in C++ are used to avoid memory leaks especially when your class contains unmanaged code, i.e., contains pointers or object handles to files, databases or other external objects.


2 Answers

The answer really lies in the statement:

    Base* virtual_derived = new VirtualDerived;

You are trying to 'free' an address that was not returned by 'malloc'. To understand why, replace this line with

    VirtualDerived* x = new VirtualDerived;
    Base* virtual_derived = x;

If you print these two addresses, you will notice that 'x' and 'virtual_derived' have different values. The address that 'malloc' returned (via 'new') is 'x' and the address that was passed to 'free' (via 'delete') is 'virtual_derived'.

like image 136
satyag Avatar answered Oct 05 '22 12:10

satyag


You have to declare the destructor in the base class as virtual, which you do not do in this example. Declaring it as virtual in the derived class only is not sufficient.

like image 44
Crowman Avatar answered Oct 05 '22 13:10

Crowman