4

I have a doubt about a question I often ask myself, this is the situation:

Two classes, no virtual destructor

class Base
{
    int myInt;
};

class Derived : public Base
{
    int myIntDerived;
};

int main()
{
    Base    *base    = new Derived;
    Derived *derived = new Derived;

    delete base;
    delete derived;
}

Is it right to say that the first delete causes a memory leak while the second one its fine?

YSC
  • 38,212
  • 9
  • 96
  • 149
Fra
  • 176
  • 2
  • 7
  • In practice, it all works and with no memory leak. In theory it is undefined behavior and anything could happen. In practice, the kind of memory leak you are asking about happens when `Derived` owns memory allocated separately. – JSF Dec 28 '15 at 13:43

2 Answers2

16

Is it right to say that the first delete causes a memory leak while the second one its fine?

The second one is indeed fine (although, you wouldn't want to delete pointers directly in real programs. One should use smart pointers instead), but your first statement isn't exactly correct.

Formally, deleting an object through a pointer to a base subobject that has a non-virtual destructor has undefined behaviour. A memory leak is possible but not necessary. In fact, in your case, since neither derived nor any of its member objects allocate any dynamic memory that would be deallocated in the destructor, there probably won't be a leak.

Whether memory is leaked or not is really the least of your concerns when your program has undefined behaviour.

eerorika
  • 232,697
  • 12
  • 197
  • 326
10

This is Undefined Behaviour, which may, indeed, lead to memory leak:
The C++ Standard, [expr.delete], paragraph 3 [ISO/IEC 14882-2014], states:

In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.


Since no destructor in neither Base nor Derived is user-defined, a default destructor is added by the compiler. Those destructors are not virtual.

Since base is a Base*, delete base calls the destructor of the base class, which is Undefined Behaviour. In concrete terms, it leads to memory leak when you work with resources; in your case, since your classes only contain POD, I'd say there is no leak.

In order to fix the memory leak, one should define a virtual destructor for classes meant to be inherited:

struct Base
{
    virtual ~Base() {}
    int myInt;
};

struct Derived : Base
{
    int myIntDerived;
};

int main()
{
    Base    *base    = new Derived;
    Derived *derived = new Derived;

    delete base;    // OK
    delete derived; // OK
}
YSC
  • 38,212
  • 9
  • 96
  • 149