108

Is there ever a good reason to not declare a virtual destructor for a class? When should you specifically avoid writing one?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Mag Roader
  • 6,850
  • 8
  • 32
  • 27

12 Answers12

82

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.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
sep
  • 3,409
  • 4
  • 29
  • 32
  • fine overview. i dropped my answer in favour of this. +1 :) – Johannes Schaub - litb Nov 19 '08 at 04:47
  • 31
    This is not a good answer. "There is no need" is different from "should not", and "no intention" is different from "made impossible". – Windows programmer Nov 19 '08 at 04:59
  • 5
    Also add: no intention to delete an instance via a base class pointer. – Adam Rosenfield Nov 19 '08 at 15:24
  • 9
    This doesn't really answer the question. Where is your good reason not to use a virtual dtor? – mxcl Nov 19 '08 at 15:25
  • 10
    I think that when there is no need to do something, that is a good reason not to do it. Its following the Simple Design principle of XP. – sep Nov 20 '08 at 01:34
  • 14
    By saying you have "no intention", you're making a huge assumption about how your class will get used. It seems to me the simplest solution in most cases (which should therefore the default) should be to have virtual destructors, and only avoid them if you have a specific reason not to. So I'm still curious about what would be a good reason. – ckarras Jun 02 '10 at 22:46
  • 1
    It's not related to the heap exactly, but more to lexical variable scoping. Any local variable's value, when it's the object of a class, is well-known at compile time, so there can't be any confusion over what destructor to call. The values of local variables are exactly the values that are kept on the stack, not the heap; therefore only heap-allocated objects need to be careful of which destructor will be called. – Luke Maurer Oct 24 '12 at 02:38
  • @Windowsprogrammer: So true! How many of us have made the rookie mistake of inheriting from std::vector? Almost always this is a terrible idea, but perfectly encapsulates "should not" vs "cannot / made impossible". – kevinarpe Aug 16 '16 at 15:01
  • Please correct me if I'm wrong, but it is said that when **any** condition applies, but: _No instantiation on the heap_ , you can have a *subclass* with dynamic memory and the following code will leak resources: `Base *b = new Derived(); delete b;` [see](https://stackoverflow.com/questions/461203/when-to-use-virtual-destructors) – Frank Sebastià Jan 03 '18 at 08:30
  • 1
    @FrankSebastià allocation with new is allocation on the heap. – Andy Borrell Sep 03 '19 at 20:42
  • 1
    @FrankSebastià I see what you mean and the second point should be clarified to: No instantiation on the heap of derived classes. – Hans Olsson Nov 20 '20 at 11:20
75

To answer the question explicitly, i.e. when should you not declare a virtual destructor.

C++ '98/'03

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.

struct A {
  // virtual ~A ();
  int i;
  int j;
};
void foo () { 
  A a = { 0, 1 };  // Will fail if virtual dtor declared
}

In an extreme case, such a change can also cause undefined behaviour where the class is being used in a way that requires a POD, e.g. passing it via an ellipsis parameter, or using it with memcpy.

void bar (...);
void foo (A & a) { 
  bar (a);  // Undefined behavior if virtual dtor declared
}

[* 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.]

Modern C++

In recent versions of C++, the concept of POD was split between the class layout and its construction, copying and destruction.

For the ellipsis case, it is no longer undefined behavior it is now conditionally-supported with implementation-defined semantics (N3937 - ~C++ '14 - 5.2.2/7):

...Passing a potentially-evaluated argument of class type (Clause 9) having a non-trivial copy constructor, a non-trivial move constructor, or a on-trivial destructor, with no corresponding parameter, is conditionally-supported with implementation-defined semantics.

Declaring a destructor other than =default will mean it's not trivial (12.4/5)

... A destructor is trivial if it is not user-provided ...

Other changes to Modern C++ reduce the impact of the aggregate initialization problem as a constructor can be added:

struct A {
  A(int i, int j);
  virtual ~A ();
  int i;

  int j;
};
void foo () { 
  A a = { 0, 1 };  // OK
}
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Richard Corden
  • 21,389
  • 8
  • 58
  • 85
  • 1
    You're right, and I was wrong, performance isn't the only reason. But this shows I was right about the rest of it: the class's programmer had better include code to prevent the class from ever being inherited by anyone else. – Windows programmer Nov 20 '08 at 02:04
  • dear Richard, can you please comment a little bit more on what you have written. I do not understand your point, but it seems the only valuable point that I have found by googling) Or may be you can give a link to a more detailed explanation? – John Smith Jun 23 '17 at 17:20
  • 2
    @JohnSmith I've updated the answer. Hopefully this helps. – Richard Corden Jun 29 '17 at 11:50
30

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.

Andy
  • 3,004
  • 2
  • 22
  • 12
  • 3
    And, in fact, there is a warning option on gcc which warns on precisely that case (virtual methods but no virtual dtor). – CesarB Nov 19 '08 at 10:32
  • 6
    Don't you then run the risk of leaking memory if you derive from the class, regardless of whether you have other virtual functions? – Mag Roader Nov 19 '08 at 22:32
  • 1
    I agree with mag. This use of a virtual destructor and or virtual method are separate requirements. Virtual destructor provide the ability for a class to perform cleanup (e.g. delete memory, close files, etc...) AND also ensures the constructors of all its members gets called. – user48956 May 12 '11 at 00:14
  • @MagRoader In theory you do, but since you only get problem if you store (and delete) a pointer to a derived object allocated on the heap in a pointer to base the obvious question is what use there is of that pointer without virtual functions? I can only see one possibility: you ONLY use the object to delete resources when "done"; and in that case you should have a virtual destructor without any other methods. – Hans Olsson Nov 26 '20 at 10:53
7

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 deleteing 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.

Jay Conrod
  • 28,943
  • 19
  • 98
  • 110
  • "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." should be emphasized more in every answer i see – csguy Nov 25 '19 at 06:55
5

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.

mxcl
  • 26,392
  • 12
  • 99
  • 98
5

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.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 3
    Polymorphic use doesn't imply polymorphic deletion. There are plenty of use cases for a class to have virtual methods yet no virtual destructor. Consider a typical statically defined dialog box, in pretty much any GUI toolkit. The parent window will destroy the child objects, and it knows the exact type of each, yet all the child windows will also be used polymorphically in any number of places, such as hit testing, drawing, accessibility APIs that fetch the text for text-to-speech engines, etc. – Ben Voigt Apr 12 '10 at 23:41
  • 4
    True, but the questioner is asking when you should specifically avoid a virtual destructor. For the dialog box you describe, a virtual destructor is pointless, but IMO not harmful. I'm not sure I'd be confident that I'll never need to delete a dialog box using a base class pointer - for example I may in future want my parent window to create its child objects using factories. So it's not a question of *avoiding* virtual destructor, just that you might not bother having one. A virtual destructor on a class not suitable for derivation *is* harmful, though, because it's misleading. – Steve Jessop Apr 13 '10 at 08:24
4

A good reason for not declaring a destructor as virtual is when this saves your class from having a virtual function table added, and you should avoid that whenever possible.

I know that many people prefer to just always declare destructors as virtual, just to be on the safe side. But if your class does not have any other virtual functions then there is really, really no point in having a virtual destructor. Even if you give your class to other people who then derive other classes from it then they would have no reason to ever call delete on a pointer that was upcast to your class - and if they do then I would consider this a bug.

Okay, there is one single exception, namely if your class is (mis-)used to perform polymorphic deletion of derived objects, but then you - or the other guys - hopefully know that this requires a virtual destructor.

Put another way, if your class has a non-virtual destructor then this is a very clear statement: "Don't use me for deleting derived objects!"

kidfisto
  • 41
  • 1
3

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.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
1

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.

Jørn Jensen
  • 998
  • 1
  • 10
  • 17
1

If you absolutely positively must ensure that your class does not have a vtable then you must not have a virtual destructor as well.

This is a rare case, but it does happen.

The most familiar example of a pattern that does this are the DirectX D3DVECTOR and D3DMATRIX classes. These are class methods instead of functions for the syntactic sugar, but the classes intentionally do not have a vtable in order to avoid the function overhead because these classes are specifically used in the inner loop of many high-performance applications.

Lisa
  • 439
  • 2
  • 8
0

On operation that will be performed on the base class, and that should behave virtually, should be virtual. If deletion can be performed polymorphically through the base class interface, then it must behave virtually and be virtual.

The destructor has no need to be virtual if you don't intend to derive from the class. And even if you do, a protected non-virtual destructor is just as good if deletion of base class pointers isn't required.

icecrime
  • 74,451
  • 13
  • 99
  • 111
-8

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.

Windows programmer
  • 7,871
  • 1
  • 22
  • 23
  • Polymorphism will certainly slow things down. Compare it with a situation where we need polymorphism and choose not to, it will be even slower. Example: we implement all the logic at the base class destructor, using RTTI and a switch statement to clean up resources. – sep Nov 20 '08 at 01:42
  • 2
    In C++, it's not your responsibility to stop me inheriting from your classes that you've documented are not suitable for use as base classes. It's my responsibility to use inheritance with caution. Unless house style guide says otherwise, of course. – Steve Jessop Nov 21 '08 at 13:43
  • 1
    ... just making the destructor virtual doesn't mean the class will necessarily work correctly as a base class. So marking it virtual "just because", instead of making that assessment, is writing a check my code can't cash. – Steve Jessop Nov 21 '08 at 13:44