Categories
c++ polymorphism shared-ptr virtual-destructor

When to use virtual destructors?

1768

I have a solid understanding of most OOP theory but the one thing that confuses me a lot is virtual destructors.

I thought that the destructor always gets called no matter what and for every object in the chain.

When are you meant to make them virtual and why?

10

  • 7

    See this: Virtual Destructor

    – Naveen

    Jan 20, 2009 at 13:04

  • 184

    Every destructor down gets called no matter what. virtual makes sure it starts at the top instead of the middle.

    Jun 29, 2013 at 0:32

  • 18

    related question: When should you not use virtual destructors?

    – Eitan T

    Aug 4, 2013 at 16:39

  • 2

    I’m also confused by @MooingDuck ‘s answer. Shouldn’t it be up instead of down, if you use the notion of subclass (under) and superclass (above)?

    – Nibor

    Jun 20, 2019 at 9:31


  • 2

    @Nibor: Yes, if you use that notion. About half the people I talk to view superclasses as “above”, and half view superclasses as “below”, so both are conflicting standards, which makes everything confusing. I think superclass as “above” is slightly more common, but that’s not the way I was taught 🙁

    Jun 20, 2019 at 17:09

1798

Virtual destructors are useful when you might potentially delete an instance of a derived class through a pointer to base class:

class Base 
{
    // some virtual methods
};

class Derived : public Base
{
    ~Derived()
    {
        // Do some important cleanup
    }
};

Here, you’ll notice that I didn’t declare Base’s destructor to be virtual. Now, let’s have a look at the following snippet:

Base *b = new Derived();
// use b
delete b; // Here's the problem!

Since Base’s destructor is not virtual and b is a Base* pointing to a Derived object, delete b has undefined behaviour:

[In delete b], if the static type of the
object to be deleted is different from its dynamic type, the static
type shall be a base class of the dynamic type of the object to be
deleted and the static type shall have a virtual destructor or the
behavior is undefined
.

In most implementations, the call to the destructor will be resolved like any non-virtual code, meaning that the destructor of the base class will be called but not the one of the derived class, resulting in a resources leak.

To sum up, always make base classes’ destructors virtual when they’re meant to be manipulated polymorphically.

If you want to prevent the deletion of an instance through a base class pointer, you can make the base class destructor protected and nonvirtual; by doing so, the compiler won’t let you call delete on a base class pointer.

You can learn more about virtuality and virtual base class destructor in this article from Herb Sutter.

16

  • 235

    This would explain why i had massive leaks using a factory i made before. All makes sense now. Thanks

    – Lodle

    Jan 20, 2009 at 13:08

  • 14

    Well, this is a bad example as there are no data members. What if Base and Derived have all automatic storage variables? ie there is no “special” or additional custom code to execute in the destructor. Is it ok then to leave off writing any destructors at all? Or will the derived class still have a memory leak?

    – bobobobo

    Jul 8, 2012 at 18:27

  • 4

  • 46

    From the Herb Sutter’s article: “Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.”

    – Sundae

    Feb 9, 2016 at 8:22

  • 4

    Also from the article – ‘if you delete polymorphically without a virtual destructor, you summon the dreaded specter of “undefined behavior,” a specter I personally would rather not meet in even a moderately well-lit alley, thank you very much.’ lol

    – Bondolin

    Feb 29, 2016 at 14:30

288

A virtual constructor is not possible but virtual destructor is possible.
Let us experiment…….

#include <iostream>

using namespace std;

class Base
{
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

The above code output the following:

Base Constructor Called
Derived constructor called
Base Destructor called

The construction of derived object follow the construction rule but when we delete the “b” pointer(base pointer) we have found that only the base destructor is called. But this must not happen. To do the appropriate thing, we have to make the base destructor virtual.
Now let see what happens in the following:

#include <iostream>

using namespace std;

class Base
{ 
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    virtual ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

The output changed as following:

Base Constructor Called
Derived Constructor called
Derived destructor called
Base destructor called

So the destruction of the base pointer (which takes an allocation on derived object!) follows the destruction rule, i.e first the Derived, then the Base.
On the other hand, there is nothing like a virtual constructor.

6

  • 1

    ” virtual constructor is not possible” means you need not write virtual constructor by your own. Construction of derived object must follow the chain of construction from derived to base. So you need not write the virtual keyword for your constructor. Thanks

    Apr 19, 2013 at 6:50

  • 5

    @Murkantilism, “virtual constructors cannot be done” is true indeed. A constructor cannot be marked virtual.

    – cmeub

    Apr 21, 2013 at 20:09

  • 1

    @cmeub, But there is an idiom to achieve what you would want from a virtual constructor. See parashift.com/c++-faq-lite/virtual-ctors.html

    – cape1232

    Oct 3, 2013 at 12:58

  • @TunvirRahmanTusher could you please explain why the Base Destructor is called??

    Nov 11, 2017 at 8:49

  • @rimiro Its automatic by c++.you can follow the link stackoverflow.com/questions/677620/…

    Nov 11, 2017 at 12:01

214

Declare destructors virtual in polymorphic base classes. This is Item 7 in Scott Meyers’ Effective C++. Meyers goes on to summarize that if a class has any virtual function, it should have a virtual destructor, and that classes not designed to be base classes or not designed to be used polymorphically should not declare virtual destructors.

7

  • 20

    +”If a class has any virtual function, it should have a virtual destructor, and that classes not designed to be base classes or not designed to be used polymorphically should not declare virtual destructors.”: Are there cases in which it makes sense to break this rule? If not, would it make sense to have the compiler check this condition and issue an error is it is not satisfied?

    – Giorgio

    May 6, 2012 at 9:29

  • @Giorgio I don’t know of any exceptions to the rule. But I wouldn’t rate myself as a C++ expert, so you may want to post this as a separate question. A compiler warning (or a warning from a static analysis tool) makes sense to me.

    May 6, 2012 at 13:08

  • 12

    Classes can be designed not to be deleted through a certain type’s pointer, yet still have virtual functions – typical example is a callback interface. One does not delete his implementation through a callback interface pointer as that’s only for subscribing, but it does have virtual functions.

    – dascandy

    Jan 15, 2016 at 5:05

  • 5

    @dascandy Exactly – that or all the many other situations where we use polymorphic behaviour but don’t perform storage management via pointers – e.g. maintaining automatic or static-duration objects, with pointers only used as observation routes. No need/purpose in implementing a virtual destructor in any such cases. Since we’re just quoting people here, I prefer Sutter from above: “Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.” The latter ensures anyone accidentally trying to delete via a base pointer is shown the error of their ways

    Apr 23, 2016 at 15:58


  • 1

    @Giorgio There is actually a trick one can use and avoid a virtual call to a destructor: bind via a const reference a derived object to a base, like const Base& = make_Derived();. In this case, the destructor of the Derived prvalue will be called, even if it’s not virtual, so one saves the overhead introduced by vtables/vpointers. Of course the scope is quite limited. Andrei Alexandrescu mentioned this in his book Modern C++ Design.

    – vsoftco

    Nov 2, 2016 at 20:06