Is there ever a good reason to not declare a virtual destructor for a class? When should you specifically avoid writing one?
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 in a pointer of a superclass
No specific reason to avoid it unless you are really so pressed for memory.
I declare a virtual destructor if and only if I have virtual methods. Once I have virtual methods, I don't trust myself to avoid instantiating it on the heap or storing a pointer to the base class. Both of these are extremely common operations and will often leak resources silently if the destructor is not declared virtual.
A virtual destructor is needed whenever there is any chance that delete
might be called on a pointer to an object of a subclass with the type of your class. This makes sure the correct destructor gets called at run time without the compiler having to know the class of an object on the heap at compile time. For example, assume B
is a subclass of A
:
A *x = new B;
delete x; // ~B() called, even though x has type A*
If your code is not performance critical, it would be reasonable to add a virtual destructor to every base class you write, just for safety.
However, if you found yourself delete
ing a lot of objects in a tight loop, the performance overhead of calling a virtual function (even one that's empty) might be noticeable. The compiler cannot usually inline these calls, and the processor might have a difficult time predicting where to go. It is unlikely this would have a significant impact on performance, but it's worth mentioning.
The performance answer is the only one I know of which stands a chance of being true. If you've measured and found that de-virtualizing your destructors really speeds things up, then you've probably got other things in that class that need speeding up too, but at this point there are more important considerations. Some day someone is going to discover that your code would provide a nice base class for them and save them a week's work. You'd better make sure they do that week's work, copying and pasting your code, instead of using your code as a base. You'd better make sure you make some of your important methods private so that no one can ever inherit from you.
I usually declare the destructor virtual, but if you have performance critical code that is used in an inner loop, you might want to avoid the virtual table lookup. That can be important in some cases, like collision checking. But be careful about how you destroy those objects if you use inheritance, or you will destroy only half of the object.
Note that the virtual table lookup happens for an object if any method on that object is virtual. So no point in removing the virtual specification on a destructor if you have other virtual methods in the class.
To answer the question explicitly, ie. when should you not declare a virtual destructor.
Adding a virtual destructor might change your class from being POD (Plain Old Data)*
or Aggregate to Non-POD. This can stop your project from compiling if your class type is aggregate initialized somewhere.
In an extreme case, such a change can also cause undefined behaviour where the class is being used n a way that requires a POD, eg. passing it via an ellipsis parameter, or using it with memcpy.
*
A POD type is a type that has specific guarantees about its memory layout. The standard really only says that if you were to copy from an object with POD type into an array of chars (or unsigned chars) and back again, then the result will be the same as the original object.]
Virtual functions mean every allocated object increases in memory cost by a virtual function table pointer.
So if your program involves allocating a very large number of some object, it would be worth avoiding all virtual functions in order to save the additional 32 bits per object.
In all other cases, you will save yourself debug misery to make the dtor virtual.
Not all C++ classes are suitable for use as a base class with dynamic polymorphism.
If you want your class to be suitable for dynamic polymorphism, then its destructor must be virtual. In addition, any methods which a subclass could conceivably want to override (which might mean all public methods, plus potentially some protected ones used internally) must be virtual.
If your class is not suitable for dynamic polymorphism, then the destructor should not be marked virtual, because to do so is misleading. It just encourages people to use your class incorrectly.
Here's an example of a class which would not be suitable for dynamic polymorphism, even if its destructor were virtual:
class MutexLock {
mutex *mtx_;
public:
explicit MutexLock(mutex *mtx) : mtx_(mtx) { mtx_->lock(); }
~MutexLock() { mtx_->unlock(); }
private:
MutexLock(const MutexLock &rhs);
MutexLock &operator=(const MutexLock &rhs);
};
The whole point of this class is to sit on the stack for RAII. If you're passing around pointers to objects of this class, let alone subclasses of it, then you're Doing It Wrong.
If you have a very small class with a huge number of instances, the overhead of a vtable pointer can make a difference in your program's memory usage. As long as your class doesn't have any other virtual methods, making the destructor non-virtual will save that overhead.