1

Consider the following example:

#include <iostream>

class Base
{
public:
  Base() { std::wcout << L"Base cons" << std::endl; }
  ~Base() { std::wcout << L"Base des" << std::endl; }
};

class Derived : public Base
{
public:
  Derived() { std::wcout << L"Derived cons" << std::endl; }
  ~Derived() { std::wcout << L"Derived des" << std::endl; }
};

int main()
{
  Base * derived = new Derived;
  std::wcout << L"Deleting..." << std::endl;
  delete derived; // Base::~Base() is not virtual so only Base::~Base() is called

  return 0;
}

// Ouput
// Base cons
// Derived cons
// Deleting...
// Base des

Since Base::~Base() is not virtual, when the object "derived" is deleted, only Base::~Base() will be executed. Wouldn't it be a memory leak if we don't call Derived::~Derived() too? Of course this is easily remedied by marking the Base::~Base() deconstructor as virtual, but what is a scenario that one would want to destruct the base derived class and not the derived class?

(It's my understanding that once the base class destructor is invoked, the derived object is no longer in a usable state)

I realize C++ is designed for efficiency -- "only pay for what you need" -- so I'm really just looking to understand why declaring a derived class does NOT require a virtual base class deconstructor (to avoid the inherent memory leak of not cleaning up the derived class)

Thanks for your insights in advance.

digitale
  • 645
  • 4
  • 13
  • @Christophe - fixed typo; Thanks – digitale Apr 03 '16 at 00:00
  • 1
    Seems like a duplicate of http://stackoverflow.com/questions/7403883/derived-class-with-non-virtual-destructor – BaseZen Apr 03 '16 at 00:07
  • 1
    "Since Base::~Base() is not virtual, when the object "derived" is deleted, only Base::~Base() will be executed. Wouldn't it be a memory leak if we don't call Derived::~Derived() too?" Worse: if you delete something via a pointer to a base class, if the base class doesn't have a virtual destructor you get undefined behavior. – GManNickG Apr 03 '16 at 00:09
  • 1
    I am interpreting this question to be, basically, "Why are these stupidly incorrect non-virtual base destructors even allowed, when their primary (maybe even only?) purpose is to allow subtle errors to arise?" Presumably the answer is that it allows the compiler to produce a more efficient program in some cases (since, of course, the programmer is free to refrain from deleting a derived object through a base pointer). But answerers do not seem to be focusing on the details of that efficiency advantage. Maybe clarification is in order? – mjwach Apr 03 '16 at 01:15
  • Thanks to everyone who contributed to answering my question. I now understand that deleting a derived object through it's non-virtual base is undefined behavior. This is permitted by the language because using virtual incurs vtable/indirection overhead that is not necessary if the programmer never deletes using the base (probably should have the destructor in the protected section in the base to ensure this cannot happen) – digitale Apr 03 '16 at 15:54

3 Answers3

2

It's not necessarily a memory leak to execute delete derived where derived is of type Base*. Because when Base doesn't have a virtual destructor this is Undefined Behavior. Anything or nothing can happen, including that what you expect to happen, happens.

Note that this situation can occur with a unique_ptr<Base> whose value was copied from a unique_ptr<Derived>. So this is one situation when this particular smart pointer is not-so-smart. Worth keeping in mind.

However, it's safe with a shared_ptr, because with a shared_ptr the original pointer is kept in the control block and used for deletion.


Regarding the question in the title,

When would one NOT want a derived class's deconstructor to execute?

… that's only when one does not want object destruction at all.

The only example I can think of is possibly a logger object.


Regarding the question at the end in the question text,

I'm really just looking to understand why declaring a derived class does NOT require a virtual base class deconstructor

… this is a different question.

As a concrete example, with Microsoft's COM technology the IUnknown interface that every COM class inherits from, does not have a virtual destructor. It doesn't need to because any COM-object self-destructs when its reference count goes to zero. And the self-destruct code has access to the most derived class.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • But if the language did require these COM base types to have virtual destructors, then safety would be gained, and (maybe?) nothing would be harmed. So why doesn't it? (That is what I interpreted the question to be in part asking, and at any rate, it's something I am now wondering about.) – mjwach Apr 03 '16 at 01:22
  • 1
    Virtual inheritance is not forced because there can be additional overhead at runtime for keeping track of an object's type and how to access its members. Something called a VTable can be used to keep a list of pointers to member functions, which entails additional inderection for function calls, as well as an increase in the object's size. – Christopher Oicles Apr 03 '16 at 04:46
  • Thanks for pointing out the undefined behavior risk -- and potential pitfall of invoking such by copying between std::unique_ptr objects. – digitale Apr 03 '16 at 15:43
1

The only scenario where you don't want to have a destructor virtual would be situations where a virtual destructor is not needed. Basically, a self-made prophecy.

If there is no possibility that an object would get destroyed using a pointer to its superclass, and the object has no other virtual methods, then not declaring a virtual destructor generates a little bit more efficient code.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
0

if the derived class does not add any memory (just changes behavior, for example), you could save some CPU cycles this way (as there is nothing there to 'leak').

Probably not a good idea - let the compiler do such optimizations.

Aganju
  • 6,295
  • 1
  • 12
  • 23