Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are destructors not virtual by default [C++]

Why doesn't C++ make destructors virtual by default for classes that have at least one other virtual function? In this case adding a virtual destructor costs me nothing, and not having one is (almost?) always a bug. Will C++0x address this?

like image 435
Jeff Linahan Avatar asked Jul 08 '11 01:07

Jeff Linahan


People also ask

Are default destructors virtual?

The destructor is not user-provided (meaning, it is either implicitly declared, or explicitly defined as defaulted on its first declaration) The destructor is not virtual (that is, the base class destructor is not virtual)

Why do destructors need to be virtual?

Virtual destructors in C++ are used to avoid memory leaks especially when your class contains unmanaged code, i.e., contains pointers or object handles to files, databases or other external objects. A destructor can be virtual.

What is Default destructor C?

The default destructor calls the destructors of the base class and members of the derived class. The destructors of base classes and members are called in the reverse order of the completion of their constructor: The destructor for a class object is called before destructors for members and bases are called.

What happens if destructor is not virtual?

Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results in undefined behavior.


2 Answers

You don't pay for what you don't need. If you never delete through base pointer, you may not want the overhead of the indirected destructor call.

Perhaps you were thinking that the mere existence of the vtable is the only overhead. But each individual function dispatch has to be considered, too, and if I want to make my destructor call dispatch directly, I should be allowed to do so.

It would be nice of your compiler to warn you if you do ever delete a base pointer and that class has virtual methods, I suppose.

Edit: Let me pull Simon's excellent comment in here: Check out this SO question on the code generated for destructors. As you can see, there's also code-bloat overhead to be considered.

like image 146
Kerrek SB Avatar answered Sep 20 '22 08:09

Kerrek SB


Here's an example (not that I recommend writing such code):

struct base {     virtual void foo() const = 0;     virtual void bar () const = 0; };  struct derived: base {     void foo() const {}     void bar() const {} };  std::shared_ptr<base> make_base() {     return std::make_shared<derived>(); } 

This is perfectly fine code that does not exhibit UB. This is possible because std::shared_ptr uses type-erasure; the final call to delete will delete a derived*, even if the last std::shared_ptr to trigger destruction is of type std::shared_ptr<void>.

Note that this behaviour of std::shared_ptr is not tailored to virtual destruction; it has a variety of other uses (e.g. std::shared_ptr<FILE> { std::fopen( ... ), std::fclose }). However since this technique already pays the cost of some indirection to work, some users may not be interested in having a virtual destructor for their base classes. That's what "pay only for what you need" means.

like image 42
Luc Danton Avatar answered Sep 21 '22 08:09

Luc Danton