59

Java and C# support the notion of classes that can't be used as base classes with the final and sealed keywords. In C++ however there is no good way to prevent a class from being derived from which leaves the class's author with a dilemma, should every class have a virtual destructor or not?


Edit: Since C++11 this is no longer true, you can specify that a class is final.


On the one hand giving an object a virtual destructor means it will have a vtable and therefore consume 4 (or 8 on 64 bit machines) additional bytes per-object for the vptr.

On the other hand if someone later derives from this class and deletes a derived class via a pointer to the base class the program will be ill-defined (due to the absence of a virtual destructor), and frankly optimizing for a pointer per object is ridiculous.

On the gripping hand having a virtual destructor (arguably) advertises that this type is meant to be used polymorphically.

Some people think you need an explicit reason to not use a virtual destructor (as is the subtext of this question) and others say that you should use them only when you have reason to believe that your class is to be derived from, what do you think?

Community
  • 1
  • 1
Motti
  • 110,860
  • 49
  • 189
  • 262
  • 1
    There are already questions asking for the pros an cons - is this a duplicate, or is it intended as an opinion poll? If the latter, maybe you should create "yes" and "no" answers for voting, then close the question? I think that's the recommended way of implementing a multiple-choice poll on SO. – Steve Jessop Dec 09 '08 at 19:01
  • 1
    Duplicates: http://stackoverflow.com/questions/270917/why-should-i-declare-a-virtual-destructor-for-an-abstract-class-in-c, http://stackoverflow.com/questions/300986/when-should-you-not-use-virtual-destructors – Steve Jessop Dec 09 '08 at 19:04
  • 7
    "and frankly optimizing for a pointer per object is ridiculous. " - Its not ridiculous for small objects. C++0x is adding a container forward_list, precisely because sometimes one pointer per object overhead is too much - from the space and time requirements. – Greg Rogers Dec 09 '08 at 19:23
  • 1
    @onebyone, this question is not a duplicate of the first question you list which is specific for *abstract* classes and I reference the second one in my question, I don't think this is a duplicate is that the question is strongly biased towards having vritual dtors an I wanted a n open discussion. – Motti Dec 09 '08 at 19:44
  • @Kyralessa, a geek's gotta do what a geek's gotta do :) – Motti Nov 04 '17 at 18:10
  • Does this answer your question? [Why should I declare a virtual destructor for an abstract class in C++?](https://stackoverflow.com/questions/270917/why-should-i-declare-a-virtual-destructor-for-an-abstract-class-in-c) – bobobobo Apr 01 '21 at 19:28
  • @bobobobo this question was not about abstract classes, so no, not really. – Motti Apr 04 '21 at 08:13

7 Answers7

63

Every abstract class should either have a,

  • protected destructor, or,
  • virtual destructor.

If you've got a public non-virtual destructor, that's no good, since it allows users to delete through that pointer a derived object. Since as we all know, that's undefined behavior.

For an abstract class, you already need a virtual-table pointer in the object, so making the destructor virtual doesn't (as far as I'm aware) have a high cost in terms of space or runtime performance. And it has the benefit that derived classes automatically have their destructors virtual (see @Aconcagua's comment). Of course, you can also make the destructor protected virtual for this case.

For a non-abstract class not intended to be deleted through a pointer to it, I don't think there's good reason to have a virtual destructor. It would waste resources, but more importantly it would give users a wrong hint. Just think about what weird sense it would make to give std::iterator a virtual destructor.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 3
    Or struct tm from , which would cease to be POD and therefore no longer be compatible with C calling conventions. – Steve Jessop Dec 09 '08 at 19:12
  • great answer, litb. I'm going to go change all of my code right now. – e.James Dec 09 '08 at 19:14
  • Late addition, I know – but I don't agree on the protected destructor. Someone might overlook the necessity to make the then public destructor of a derived class virtual again, and someone else might derive from derived assuming an already virtual destructor – and (illegally) delete grand-child via pointer to child... Sure, second person did the error then, but it would have been avoided if the destructor was already virtual in very first base class, so from a safety point of view I only consider second option valid (abstract classes only, of course). – Aconcagua Feb 21 '20 at 09:42
  • @Aconcagua My rule for the second author would be: Every non-abstract instantiatable class should either have a virtual public destructor, or non-virtual public destructor and declared `final`. – Johannes Schaub - litb Feb 22 '20 at 21:09
  • Your idea to give every abstract class a virtual destructor sounds interesting though. Maybe I should adopt it. My example with `std::iterator` is somewhat poor, because `std::iterator` isn't abstract at all. I'll amend. – Johannes Schaub - litb Feb 22 '20 at 21:14
  • @JohannesSchaub-litb >"Every **non-abstract instantiatable class** should either have a virtual public destructor, or non-virtual public destructor and declared final. "? What's "non-abstract instantiatable class"? The base class? – John Aug 25 '21 at 03:40
32

The question is really, do you want to enforce rules about how your classes should be used? Why? If a class doesn't have a virtual destructor, anyone using the class knows that it is not intended to be derived from, and what limitations apply if you try it anyway. Isn't that good enough?

Or do you need the compiler to throw a hard error if anyone dares to do something you hadn't anticipated?

Give the class a virtual destructor if you intend for people to derive from it. Otherwise don't, and assume that anyone using your code is intelligent enough to use your code correctly.

jalf
  • 243,077
  • 51
  • 345
  • 550
11

No! Virtual destructors are used only when a object of a derived class is deleted through a base class pointer. If your class is not intended to serve as the base in this scenario, don't make the destructor virtual - you would be sending a wrong message.

Nemanja Trifunovic
  • 24,346
  • 3
  • 50
  • 88
  • So how do you anticipate every single instance where your code is useful? Perhaps there will be some instance where your class, which is meant to be used non-polymorphically by you is useful only as a base class in some very specific instance. – v010dya Jun 27 '16 at 05:34
5

Check this article from Herb Sutter:

Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.

Paolo Tedesco
  • 55,237
  • 33
  • 144
  • 193
  • 9
    Note that he's talking about classes that are meant to be *base* classes this question is specifically about classes not designed to be base classes. – Motti Dec 10 '08 at 19:43
  • @Paolo Tedesco "should be either public and virtual, or protected and nonvirtual **or public and non-virtual and marked `final` keyword." Am I right? – John Aug 25 '21 at 03:42
  • @John this answer is way older than c++ 11 :) – Paolo Tedesco Aug 25 '21 at 05:48
2

I would "no" to the general question. Not every class needs one. If you can know that the class should never be inherited from, then there is no need to incur the minor overhead. But if there is a chance, be on the safe side and put one in there.

Evan Teran
  • 87,561
  • 32
  • 179
  • 238
1

Base class becomes abstract class, when it contains at least one pure virtual function. If Base does not have a virtual destructor and Derived (derived from Base) does, then you can safely destroy a Derived object through a Derived object pointer but not through a Base object pointer.

0

I'll add that there have been times when I have scratched my head for a while on destructors not getting called when I forgot a virtual in the parent or child class. I guess I know to look for that now though. :)

Someone might argue that there are times the parent class does something in its destructor that a child should not do... but that's probably an indicator of something wrong with your inheritance structure anyway.

Patrick Hogan
  • 2,098
  • 4
  • 20
  • 28