Articles

Virtual destructors in C++

In C++ on November 7, 2010 by Matt Giuca Tagged: ,

A quick reminder or lesson for C++ users (a follow-up on my recent angry tweet). I vaguely recall this rule but I had forgotten it, and it just bit me. So a quick quiz: what does this code print (and in what order):

#include <iostream>

class A
{
public:
    A() { std::cout << "A()" << std::endl; }
    ~A() { std::cout << "~A()" << std::endl; }
};

class B : public A
{
public:
    B() { std::cout << "B()" << std::endl; }
    ~B() { std::cout << "~B()" << std::endl; }
};

int main()
{
    A* a = new B;
    delete a;
}

I have two classes, A and B. B is a subclass of A, and both simply print out when their constructor and destructor are called. Since in main I am constructing a new B, upcasting it to an A, then deleting it (as an A*), I would rather like to see both constructors called (upon constructing the B), and then both destructors (upon destroying the A, which is really a B):

A()
B()
~B()
~A()

What I’m actually seeing is this:

A()
B()
~A()

The destructor to B is not being called at all! This can result in some serious memory leakage.

The reason is understandable (and pretty complicated), but it still sucks: since I am deleting an A object, C++ naturally calls the A class’s destructor, ~A(). In order to call ~B(), it would have to do a dynamic lookup on the runtime type of the variable a. In order to do that, the class A would need a virtual method table, which it doesn’t have, because I didn’t declare any virtual methods. Furthermore, the method ~A() would need to be in the virtual method table, which it isn’t, because I didn’t declare it virtual.

If that doesn’t make sense to you, don’t worry. The solution is pretty simple, but necessarily manual: Add the “virtual” keyword to the ~A() method, like this:

    virtual ~A() { std::cout << "~A()" << std::endl; }

Do that for every single class which might be inherited (the C++ FAQ suggests it’s only necessary if someone will upcast a derived class and delete it, but you can never know when someone might want to do that). You even have to do this if you don’t have a destructor — you need to make one! Like this:

    virtual ~A() {}

And note that even if the derived classes don’t have destructors, this is still necessary. Not only does this issue prevent destructors from being called; it also prevents instance attributes from being destroyed automatically (like say your derived class has an instance vector field; that won’t be automatically destroyed unless the base class has a virtual destructor).

What a mess! More details are at the C++ FAQ.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: