69

I believed I searched many times about virtual destructors, most mention the purpose of virtual destructors, and why you need virtual destructors. Also I think in most cases destructors need to be virtual.

Then the question is: Why doesn't c++ set all destructors virtual by default? or in other questions:

When do I NOT need to use virtual destructors?

In which case I should NOT use virtual destructors?

What is the cost of using virtual destructors if I use it even if it is not needed?

8
  • 6
    And what if your class is not supposed to be inherited? Look at many of the standard library classes, few have virtual functions because they are not designed to be inherited. Commented May 21, 2015 at 6:34
  • 4
    Also I think in most cases destructors need to be virtual. Nope. Not at all. Only those who abuse inheritance (rather than favoring composition) think so. I have seen entire applications with only a handful of base classes and virtual functions. Commented May 21, 2015 at 11:23
  • 1
    @underscore_d With typical implementations, there would be extra code generated for any polymorphic class unless all such implicit stuff has been devirtualized and optimized away. Within common ABIs, this involves at least one vtable for each class. The layout of class also has to be changed. You can't be back reliably once you have published such a class as parts of some public interface, because changing it again would break ABI compatibility, since it's obviously bad (if ever possible) to expect devirtualization as interface contracts in general.
    – FrankHB
    Commented Oct 27, 2018 at 13:57
  • 1
    @underscore_d The phrase "at compile time" is inaccurate, but I think this means a virtual destructor cannot be trivial nor with constexpr specified, so the extra code generation is difficult to avoid (unless you totally avoid destruction of such objects at all) so it would more or less harm runtime performance.
    – FrankHB
    Commented Oct 27, 2018 at 14:01
  • 2
    @underscore_d The "pointer" seems red herring. It possibly should be a pointer to member (which is not a pointer by definition). With usual ABIs, A pointer to member is often not fit in a machine word (as typical pointers), and changing a class from non-polymorphic to polymorphic would often change the size of the pointer to member of this class.
    – FrankHB
    Commented Oct 27, 2018 at 14:05

8 Answers 8

47

If you add a virtual destructor to a class:

  • in most (all?) current C++ implementations, every object instance of that class needs to store a pointer to the virtual dispatch table for the runtime type, and that virtual dispatch table itself added to the executable image

  • the address of the virtual dispatch table is not necessarily valid across processes, which can prevent safely sharing such objects in shared memory

  • have an embedded virtual pointer frustrates creating a class with memory layout matching some known input or output format (for example, so a Price_Tick* could be aimed directly at suitably aligned memory in an incoming UDP packet and used to parse/access or alter the data, or placement-newing such a class to write data into an outgoing packet)

  • the destructor calls themselves may - under certain conditions - have to be dispatched virtually and therefore out-of-line, whereas non-virtual destructors might be inlining or optimised away if trivial or irrelevant to the caller

The "not designed to be inherited from" argument wouldn't be a practical reason for not always having a virtual destructor if it weren't also worse in a practical way as explained above; but given it is worse that's a major criterion for when to pay the cost: default to having a virtual destructor if your class is meant to be used as a base class. That's not always necessary, but it ensures the classes in the heirarchy can be used more freely without accidental undefined behaviour if a derived class destructor is invoked using a base class pointer or reference.

"in most case destructors need to be virtual"

Not so... many classes have no such need. There are so many examples of where it's unnecessary it feels silly to enumerate them, but just look through your Standard Library or say boost and you'll see there's a large majority of classes that don't have virtual destructors. In boost 1.53 I count 72 virtual destructors out of 494.

0
32

In which case I should NOT use virtual destructors?

  1. For a concrete class which doesn't want to be inherited.
  2. For a base class without polymorphic deletion. Either clients should not be able to delete polymorphically using a pointer to Base.

BTW,

In which case should use virtual destructors?

For a base class with polymorphic deletion.

2
  • 10
    +1 for #2, specifically without polymorphic deletion. If your destructor can never be invoked via a base pointer, making it virtual is unnecessary and redundant, especially if your class wasn't virtual before (so it becomes newly bloated with RTTI). To guard against any user violating this, as Herb Sutter advised, you'd make the base class's dtor protected and non-virtual, so that it can only be invoked by/after a derived destructor. Commented Apr 23, 2016 at 16:44
  • @underscore_d imho that an important point that I missed in the answers, as in the presence of inheritance the only case where I dont need a virtual constructor is when I can make sure that it is never needed Commented Jan 11, 2018 at 15:22
22

What is the cost of using virtual destructors if I use it even if it is not needed?

The cost of introducing any virtual function to a class (inherited or part of the class definition) is a possibly very steep (or not depending on the object) initial cost of a virtual pointer stored per object, like so:

struct Integer
{
    virtual ~Integer() {}
    int value;
};

In this case, the memory cost is relatively enormous. The actual memory size of a class instance will now often look like this on 64-bit architectures:

struct Integer
{
    // 8 byte vptr overhead
    int value; // 4 bytes
    // typically 4 more bytes of padding for alignment of vptr
};

The total is 16 bytes for this Integer class as opposed to a mere 4 bytes. If we stored a million of these in an array, we end up with 16 megabytes of memory usage: twice the size of the typical 8 MB L3 CPU cache, and iterating through such an array repeatedly can be many times slower than the 4 megabyte equivalent without the virtual pointer as a result of additional cache misses and page faults.

This virtual pointer cost per object, however, doesn't increase with more virtual functions. You can have 100 virtual member functions in a class and the overhead per instance would still be a single virtual pointer.

The virtual pointer is typically the more immediate concern from an overhead standpoint. However, in addition to a virtual pointer per instance is a per-class cost. Each class with virtual functions generates a vtable in memory which stores addresses to the functions it should actually call (virtual/dynamic dispatch) when a virtual function call is made. The vptr stored per instance then points to this class-specific vtable. This overhead is usually a lesser concern, but it might inflate your binary size and add a bit of runtime cost if this overhead was paid needlessly for a thousand classes in a complex codebase, e.g. This vtable side of the cost does actually increase proportionally with more and more virtual functions in the mix.

Java developers working in performance-critical areas understand this kind of overhead very well (though often described in the context of boxing), since a Java user-defined type implicitly inherits from a central object base class and all functions in Java are implicitly virtual (overridable) in nature unless marked otherwise. As a result, a Java Integer likewise tends to require 16 bytes of memory on 64-bit platforms as a result of this vptr-style metadata associated per instance, and it's typically impossible in Java to wrap something like a single int into a class without paying a runtime performance cost for it.

Then the question is: Why doesn't c++ set all destructors virtual by default?

C++ really favors performance with a "pay as you go" kind of mindset and also still a lot of bare-metal hardware-driven designs inherited from C. It doesn't want to needlessly include the overhead required for vtable generation and dynamic dispatch for every single class/instance involved. If performance isn't one of the key reasons you are using a language like C++, you might benefit more from other programming languages out there as a lot of the C++ language is less safe and more difficult than it ideally could be with performance often being the key reason to favor such a design.

When do I NOT need to use virtual destructors?

Quite often. If a class is not designed to be inherited, then it doesn't need a virtual destructor and would only end up paying a possibly large overhead for something it doesn't need. Likewise, even if a class is designed to be inherited but you never delete subtype instances through a base pointer, then it also does not require a virtual destructor. In that case, a safe practice is to define a protected nonvirtual destructor, like so:

class BaseClass
{
protected:
    // Disallow deleting/destroying subclass objects through `BaseClass*`.
    ~BaseClass() {}
};

In which case I should NOT use virtual destructors?

It's actually easier to cover when you should use virtual destructors. Quite often far more classes in your codebase will not be designed for inheritance.

std::vector, for example, is not designed to be inherited and typically should not be inherited (very shaky design), as that will then be prone to this base pointer deletion issue (std::vector deliberately avoids a virtual destructor) in addition to clumsy object slicing issues if your derived class adds any new state.

In general a class that's inherited should either have a public virtual destructor or a protected, nonvirtual one. From C++ Coding Standards, chapter 50:

50. Make base class destructors public and virtual, or protected and nonvirtual. To delete, or not to delete; that is the question: If deletion through a pointer to a base Base should be allowed, then Base's destructor must be public and virtual. Otherwise, it should be protected and nonvirtual.

One of the things C++ tends to kind of implicitly emphasize (because designs tend to get really brittle and awkward and possibly even unsafe otherwise) is the idea that inheritance is not a mechanism designed to be used as an afterthought. It's an extensibility mechanism with polymorphism in mind, but one which requires foresight as to where extensibility is needed. As a result, your base classes should be designed as roots of an inheritance hierarchy upfront, and not something you inherit from later as an afterthought without any such foresight in advance.

In those cases where you simply want to inherit to reuse existing code, composition is often strongly encouraged (Composite Reuse Principle).

0
11

Why c++ not set all destructors virtual by default? Cost of extra storage and call of virtual method table. C++ is used for system, low-latency, rt programming where this could be burden.

7
  • 1
    Destructors shouldn't used in the first place in hard real time systems since many resources like dynamic memory cannot be used in order to provide strong deadline guarantees
    – Marco A.
    Commented May 21, 2015 at 6:51
  • 10
    @MarcoA. Since when do destructors imply dynamic memory allocation?
    – chbaker0
    Commented May 21, 2015 at 6:59
  • @chbaker0 I used a 'like'. They're simply not used in my experience.
    – Marco A.
    Commented May 21, 2015 at 7:18
  • 6
    It's also nonsense that dynamic memory cannot be used in hard real-time systems. It's fairly trivial to prove that a preconfigured heap with fixed allocation sizes and an allocation bitmap will either allocate memory or return an out-of-memory condition in the time it takes to scan that bitmap.
    – MSalters
    Commented May 21, 2015 at 8:58
  • @msalters that does make me think: imagine a program where the cost of each operation was stored in the type system. Allowing compile-time checks of realtime guarantees.
    – Yakk
    Commented May 21, 2015 at 11:07
8

This is a good example of when to not use the virtual destructor: From Scott Meyers:

If a class does not contain any virtual functions, that is often an indication that it is not meant to be used as a base class. When a class is not intended to be used as a base class, making the destructor virtual is usually a bad idea. Consider this example, based on a discussion in the ARM:

// class for representing 2D points
class Point {
public:
    Point(short int xCoord, short int yCoord);
    ~Point();
private:
    short int x, y;
};

If a short int occupies 16 bits, a Point object can fit into a 32-bit register. Furthermore, a Point object can be passed as a 32-bit quantity to functions written in other languages such as C or FORTRAN. If Point's destructor is made virtual, however, the situation changes.

The moment you add virtual member,a virtual pointer is added to your class that points to virtual table for that class.

1
  • 1
    If a class does not contain any virtual functions, that is often an indication that it is not meant to be used as a base class. Wut. Does anyone else remember the Good Old Days, where we were allowed to use classes and inheritance to build up successive layers of reusable members and behaviour, without having to care about virtual methods at all? C'mon, Scott. I get the core point, but that "often" is really reaching. Commented Jun 29, 2017 at 23:28
3

A virtual destructor adds a runtime cost. The cost is especially great if the class does not have any other virtual methods. The virtual destructor is also only needed in one specific scenario, where an object is deleted or otherwise destroyed through a pointer to a base class. In this case, the base class destructor must be virtual, and the destructor of any derived class will be implicitly virtual. There are a few scenarios where a polymorphic base class is used in such a way that the destructor does not need to be virtual:

  • If instances of derived classes are not allocated on the heap, e.g. only directly on the stack or inside other objects. (Except if you use uninitialized memory and placement operator new.)
  • If instances of derived classes are allocated on the heap, but deletion happens only through pointers to the most derived class, e.g. there is a std::unique_ptr<Derived>, and the polymorphism happens only through non-owning pointers and references. Another example is when objects are allocated using std::make_shared<Derived>(). It is fine to use std::shared_ptr<Base> as well as long as the initial pointer was a std::shared_ptr<Derived>. This is because shared pointers have their own dynamic dispatch for destructors (the deleter) that does not necessarily rely on a virtual base class destructor.

Of course, any convention to use objects only in the aforementioned ways can easily be broken. Therefore, Herb Sutter's advice remains as valid as ever: "Base class destructors should either be public and virtual, or protected and non-virtual." That way, if someone attempts to delete a pointer to a base class with non-virtual destructor, (s)he will most likely receive an access violation error at compile time.

Then again there are classes that are not designed to be (public) base classes. My personal recommendation is to make them final in C++11 or higher. If it's designed to be a square peg, then chances are it will not work very well as a round peg. This is related to my preference for having an explicit inheritance contract between base class and derived class, for the NVI (non-virtual interface) design pattern, for abstract rather than concrete base classes, and my abhorrence of protected member variables, among other things, but I know all of these views are controversial to some degree.

2

There will be an overhead in the constructor for creating the vtable (if you don't have other virtual functions, in which case you PROBABLY, but not always, should have a virtual destructor too). And if you don't have any other virtual functions, it makes your object one pointer-size larger than otherwise is necessary. Obviously, the increased size can have a big impact on small objects.

There is an extra memory read to get the vtable and then call the function indirectory through that, which is overhead over non-virtual destructor when the destructor is called. And of course, as a consequence, a little extra code generated for each call to the destructor. This is for cases where the compiler can't deduce the actual type - in those cases where it can deduce the actual type, the compiler will not use the vtable, but call the destructor directly.

You should have a virtual destructor if your class is intended as a base-class, in particular if it may be created/destroyed by some other entity than the code that knows what type it is at creation, then you need a virtual destructor.

If you are not sure, use virtual destructor. It's easier to remove virtual if it shows up as a problem than it is to try to find the bug caused by "the right destructor is not called".

In short you should not have a virtual destructor if: 1. You don't have any virtual functions. 2. Do not derive from the class (mark it final in C++11, that way the compiler will tell if you try to derive from it).

In most cases, creation and destruction is not a major part of the time spent using a particular object unless there is "a lot of content" (creating a 1MB string is obviously going to take some time, because at least 1MB of data needs to be copied from wherever it currently is located). Destructing a 1MB string is no worse than destruction of a 150B string, both will require deallocating the string storage, and not much else, so the time spent there is typically the same [unless it's a debug build, where deallocation often fills memory with a "poison pattern" - but that is not how you are going to run your real application in production].

In short, there is a small overhead, but for small objects, it may make a difference.

Note also that compilers can optimise away the virtual lookup in some cases, so it's only a penalty

As always when it comes to performance, memory footprint, and such: Benchmark and profile and measure, compare the results with alternatives, and look at where MOST of the time/memory is spent, and don't try to optimise the 90% of code that isn't run much [most applications have about 10% of code that is highly influential on the execution time, and 90% of code that doesn't have much influence at all]. Do this in a high optimisation level, so you already have the benefit of the compiler doing a good job! And repeat, check again and improve stepwise. Don't try to be clever and try to figure out what is important and what isn't unless you have a lot of experience with that particular type of application.

2
  • 1
    "will be an overhead in the constructor for creating the vtable" - the vtable's usually "created" on a per-class basis by the compiler, with the constructor only having the overhead of storing a pointer to it in the object instance under construction.
    – Tony
    Commented May 21, 2015 at 9:47
  • In addition... I'm all about avoiding premature optimisation, but conversely, You **should** have a virtual destructor if your class is intended as a base-class is a gross oversimplification - and premature pessimisation. This is only needed if anyone is allowed to delete a derived class through pointer to base. In many situations, that is not so. If you know it is, then sure, incur the overhead. Which, btw, is always added, even if the actual calls can be statically resolved by the compiler. Otherwise, when you properly control what people can do with your objects, it's not worthwhile Commented Jul 25, 2016 at 11:39
1

Declaring a destructor virtual is only necessary when you plan to make your class inheritable. Usually the classes of the standard library (such as std::string) do not provide a virtual destructor and thus are not meant for subclassing.

2
  • 3
    The reason is subclassing + use of polymorphism. A virtual destructor is required only if a dynamic resolution is needed, that is a reference/pointer/whatever to the master class may actually refer to an instance of a subclass. Commented May 21, 2015 at 6:45
  • 2
    @MichelBillaud actually you can still have polymorphism without virtual dtors. A virtual dtor is ONLY required for polymorphic delete, i.e. calling delete on a pointer to a base class.
    – chbaker0
    Commented May 21, 2015 at 7:03

Not the answer you're looking for? Browse other questions tagged or ask your own question.