When Should Your Destructor Be Virtual

When should your destructor be virtual?

  1. You need virtual destructor when at
    least one of class methods is
    virtual.

This is because the reason for virtual method is that you want to use polymorphism. Meaning you will call a method on the base class pointer and you want the most derived implementation - this is the whole point of polymorphism.

Now if you did not have virtual destructor and through the pointer to base class you call destructor you end up calling base class destructor. In this case you want polymorphism to work on your destructor as well, e.g. through calling destructor on your base class you want to end up calling destructor of your most derived class not your base class.

class A
{
virtual void f() {}
~A() {}
}

class B : public A
{
void f() {}
~B() {}
}

A * thing = new B();
thing->f(); // calls B's f()
delete thing; // calls ~A(), not what you wanted, you wanted ~B()

having ~A() virtual turns on polymorphism

virtual ~A() {}

So when you now call

delete thing;

~B() will be called.

You would declare virtual destructors when you design class as an interface e.g. you expect it to be extended or implemented. A good practice in that case is to have a interface class (in the sense of Java interfaces) with virtual methods and virtual destructor and then have concrete implementation classes.

You can see that STL classes don't have virtual destructors so they are not supposed to be extended (e.g. std::vector, std::string ...). If you extend std::vector and you call destructor on base class via pointer or reference you will definitely not call your specialized class destructor which may lead to memory leaks.

When to use virtual destructors?

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.

Should the destructor be always virtual when a class is part of a larger framework?

As @Konrad Grochowski's answer states, the destructor of B is implictly virtual, so the behavior is well defined. In your example, C::~C() will be called. From the C++ spec § 12.4.8:

A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.

The more pertinent question, is what happens when your framework base class actually has a non-virtual destructor (which I think is what you were driving at), and your user derives from it. For example:

// Your framework:
class A
{
public:
A();
~A(); // non-virtual
};

// User's class:
class B : public A
{
B();
virtual ~B(); // virtual
virtual void UserMethod();
};

As discussed in this question (Non virtual destructor in base class, but virtual destructor in derived class cause segmentation fault), this could cause your users to run into problems. If you unsure whether the user will derive from your class, it should have a virtual destructor, otherwise there is a potential for problems.

To enforce proper behavior with non-virtual destructors, you could disallow the user from deriving from the class, in which case a non-virtual destructor could be safe, assuming you use the class properly within your framework. In C++11, you can use final to disallow derivation. In C++03 and below, you can use the trick here to disallow derivation.

Why is destructor always declared virtual

It's declared virtual so that inheriting classes will remember to override this method to do their own cleanup. This is important to prevent memory leaks.

When should you not use virtual destructors?

There is no need to use a virtual destructor when any of the below is true:

  • No intention to derive classes from it
  • No instantiation on the heap
  • No intention to store with access via a pointer to a superclass

No specific reason to avoid it unless you are really so pressed for memory.

Is it always necessary to declare destructor as virtual, if the class contains atleast a virtual function?

A virtual destructor ensures that the inherited class destructor is called when you have a pointer to a base class.

In this particular case you don't need it, but a user could inherite from der another class (let it be foo) which uses -for example- dynamic memory allocation. In that case the destructor wouldn't be called unless he has a pointer of type foo.

So no, it's not "necessary" but if you already have at least a virtual function (hence you already have a VTABLE) there is no harm either. It's mandatory if you assume that those class are to be inherited by the user and are freed using a pointer to the base class.

No virtual functions, but still need virtual destructor?

There is no polymorphism because you call (will call) non-virtual functions using the referemce. That is in your example you simply call (will call) functions of the base class.

Moreover this statement

base& baseVar = derived();

should not be compiled because you bind a temporary object with a non-const reference.

There must be

const base& baseVar = derived();

As for the destructor in your example then there is no need to have a virtual destructor. Becasue you defined a reference to a temporary object of the derived class. In this case for the temporary object will be called its own destructor. That is at first the destructor of the base class will be called (from the destructor of the derived class) and then the body of the destructor of the derived class will be executed.

The vertual destructor would be need if you would allocate a derived memory in the heap and assign the address of the allocated memory to a pointer of the base class. And when you would call operator delete for this pointer then if you have no virtual destructor then the only destructor of the base class would be called.

For example

class Base;
class Derived;

main()
{
base* baseVar = new derived();
delete baseVar; // base shall have a virtual destructor
}


Related Topics



Leave a reply



Submit