Virtual destructor and memory deallocation - c++

I'm not quite sure I understand virtual destructors and the concept of allocating space on the heap right. Let's look at the following example:
class Base
{
public:
int a;
};
class Derived : public Base
{
public:
int b;
};
I imagine that if I do something like this
Base *o = new Derived;
that 8 Bytes (or whatever two integers need on the system) are allocated on the heap, which looks then something like this:
... | a | b | ...
Now if I do this:
delete o;
How does 'delete' know, which type o is in reality in order to remove everything from the heap? I'd imagine that it has to assume that it is of type Base and therefore only deletes a from the heap (since it can't be sure whether b belongs to the object o):
... | b | ...
b would then remain on the heap and be unaccessible.
Does the following:
Base *o = new Derived;
delete o;
truly provoke memory leaks and do I need a virtual destructor here? Or does delete know that o is actually of the Derived class, not of the Base class? And if so, how does that work?
Thanks guys. :)

You're making a lot of assumptions about the implementation, which may
or may not hold. In a delete expression, the dynamic type must be the
same as the static type, unless the static type has a virtual
destructor. Otherwise, it is undefined behavior. Period. That's
really all you have to know—I've used with implementations where
it would crash otherwise, at least in certain cases; and I've used
implementations where doing this would corrupt the free space arena, so
that the code would crash sometime later, in a totally unrelated piece
of code. (For the record, VC++ and g++ both fall in the second case, at
least when compiled with the usual options for released code.)

Firstly, the classes you declared in your example have trivial internal structure. From purely practical point of view, in order to destroy object of such classes properly the run-time code does not need to know the actual type of the object being deleted. All it needs to know is the proper size of the memory block to be deallocated. This is actually something that is already achieved by C-style library functions like malloc and free. As you probably know, free implicitly "knows" how much memory to deallocate. Your example above does not involve anything in addition to of that. In other words, your example above is not elaborate enough to truly illustrate anything C++-specific.
However, formally the behavior of your examples is undefined, since virtual destructor is formally required by C++ language for polymorphic deletion regardless of how trivial the internal structure of the class is. So, your "how delete knows..." question simply does not apply. Your code is broken. It does not work.
Secondly, the actual tangible C++-specific effects begin to appear when you begin to require non-trivial destruction for your classes: either by defining an explicit body for the destructor or by adding non-trivial member subobjects to your class. For example, if you add a std::vector member to your derived class, the destructor of the derived class will become responsible for (implicit) destruction of that subobject. And in order for that to work, you will have to declare you destructors virtual. A proper virtual destructor is called through the same mechanism as any other virtual function is called. That's basically the answer to your question: the run-time code does not care about the actual type of the object simply because the ordinary virtual dispatch mechanism will ensure that the proper destructor is called (just like it works with any other virtual function).
Thirdly, another significant effect of virtual destruction appears when you define dedicated operator delete functions for your classes. The language specification requires that the proper operator delete function is selected as if it is looked up from inside the destructor of the class being deleted. And many implementations implement this requirement literally: they actually implicitly call operator delete from inside the class destructor. In order for that mechanism to work properly, the destructor has to be virtual.
Fourthly, a part of your question seems to suggest that you believe that failing to define a virtual destructor will lead to "memory leaks". This a popular, but completely incorrect and totally useless urban legend, perpetuated by low-quality sources. Performing polymorphic deletion on a class that has no virtual destructor leads to undefined behavior and to completely unpredictable devastating consequences, not to some "memory leaks". "Memory leaks" are not the issue in such cases.

There is no problem in the size of the object being deleted - it is known. The problem solved by virtual destructors can be demonstrated as follows:
class Base
{
public:
Base() { x = new char[1]; }
/*virtual*/ ~Base() { delete [] x; }
private:
char* x;
};
class Derived : public Base
{
public:
Derived() { y = new char[1]; }
~Derived() { delete [] y;}
private:
char* y;
};
Then having:
Derived* d = new Derived();
Base* b = new Derived();
delete d; // OK
delete b; // will only call Base::~Base, and not Derived::~Derived
The second delete will not finalize the object properly. If the virtual keyword was uncommented, then the second delete statement will behave as expected, and it will call Derived::~Derived along with Base::~Base.
As pointed out in the comments, to be strict, the second delete yields an undefined behavior, but it's used here only for the sake of making the point about virtual destructors.

Related

C++ inheritance: does lack of virtual destructor lead to memory leak? [duplicate]

This question already has answers here:
Possible memory leak without a virtual destructor?
(3 answers)
Closed 7 years ago.
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?
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.
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
}

Does the destructor get called automatically

My question is simple, but I haven't been able to find the question anywhere.
If I have a class like such
class A {
vector<int> data;
}
When an instance of A gets destroyed will data also get destroyed properly, or should I write a destructor for A that calls data's destructor? Basically I worried about whether the dynamic memory of vector will not be freed when an instance of A is destroyed. I suspect the answer is that data is freed properly, but I don't want to find out I'm wrong the hard way.
Further, if A was a struct would the destructor for data get called when a local instance of A falls out of scope?
Yes, data will be destroyed automatically, you need not do anything to achieve it. vector will handle the cleaning up of the dynamic memory allocated by it. The vector's destructor will be called automatically when an instance of A is destroyed.
There is no difference in behavior irrespective of whether A is a class or struct.
No need, data member's destructors are always called.
An explicit destructor is useful manual memory management
struct a{
int* ip;
a()
: ip(new int(5))
{ }
~a() { delete ip; }
};
That said, you should generally speaking use RAII containers (such as smart pointers) so I personally rarely write dtors there days.
And exception to that is to declare a base classes dtor as virtual.
struct base {
virtual ~base() {}
};
struct child : public base {
//base and child destructor automatically called
}
A default-destructor is created automatically by the compiler if you do not define one yourself. In general, you do not need to create your own destructor unless you have pointer data-members that "own" the memory they point to, and/or you are designing your class to be derived by other classes, at which point you would want to at least declare an empty virtual destructor.
In all cases, both with your own destructor, as well as the default compiler-created destructor, all destructors for non-static data-members as well as any base-classes of the current class are called at the end of the destructor and before the destructor function itself returns.

Non-virtual trivial destructor + Inheritance

Given that a class and all its subclasses need no more than the default destructor to release their resources if stored in a variable of the exact type (or pointer to the exact type), can a subclass leak memory if referenced by a base class pointer and then deleted by that pointer?
Example:
#include <memory>
class A {
};
class B : public A {
public:
B () : pInt(new int) {}
auto_ptr<int> pInt; // this is what might leak... possibly more will though
};
void will_this_leak () {
A *pA = new B();
delete pA;
}
"Leak memory"? Why are you talking about leaking memory specifically?
The code you posted produces undefined behavior. Anything can happen in this case: memory leaked, hard drive formatted, program crashed, etc.
P.S. I know that there's a popular urban legend out there that performing polymorphic destruction without a virtual destructor "might leak memory". I don't know who invented that nonsense and why they decided to use "leaking memory" as the primary scenario for what might happen. In reality the behavior in this case has absolutely nothing to do with "leaking memory". The behavior is simply undefined.
From the practical point of view, in your particular case it is rather obvious that there's no real chance for the destructor of your auto_ptr to get called, so the memory owned by that auto_ptr will certainly be leaked. But again, this is the least of this code's problems.
It doesn't matter whether they can leak or not. The C++ standard says that deleting a derived class via a base pointer is undefined behavior if the base does not have a virtual destructor. Specifically from 5.3.5/3:
In the first alternative (delete object), if the static type of the
operand is different from its dynamic type, the static type shall be
a base class of the operand’s dynamic type and the
static type shall have a virtual destructor or the behavior is undefined.
So once you have done such a deletion, your program is in an undefined state, and all questions about leaks are moot.
Yes, this will leak. When you delete the A*, it calls ~A(). Since ~A() is not virtual, it won't know that ~B() needs calling too.
Assuming, of course, that B inherits from A. I'm guessing that's a typo in your question -- the code as it stands won't compile :)
The code as of now exhibits undefined-behavior.
If the static type of the operand is
different from the dynamic type, then
the static type becomes the base class
and it's destructor must be virtual. Else the behavior is undefined.
#include <memory>
class A {
public :
virtual ~A() {} // This makes the derived sub-object destruction first
};
class B : public A {
public:
B () : pInt(new int) {}
auto_ptr<int> pInt;
/* There is no need to write any custom destructor
in this case. auto_ptr will effectively handle deallocating
the acquired resources from free store.
*/
};
void will_this_leak () {
A *pA = new B();
delete pA;
}
With the above changes made, there shouldn't be any undefined behavior or memory leaks.

Is the whole object freed with a non-virtual destructor and a Base class pointer?

If a Base class does not have a virtual destructor (in order to avoid the vtable entry for instance) and the Derived class has only basic attributes, does it free all the memory allocated by new, when the pointer of the Base class is deleted? I know the destructor of the Derived class will not be called but I am wondering if the memory allocated by the whole object will be freed?
I assume also that calling delete on a Derived pointer will free the whole memory space.
Also, if it does not free the Derived class part of the memory, how does it work in the same case but with of a virtual destructor in the Base class, to know how much memory to free?
Example:
class Base {
public:
int a;
int b;
Base() {}
~Base() {}
};
class Derived : public Base {
public:
int c;
int d;
Derived() {}
~Derived() {}
};
int main() {
Base *p = new Derived();
delete p; // is memory allocated for Derived freed?
}
It's undefined behavior, so anything can happen. Quote from the standard [expr.delete]:
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.
Just don't do that.
I think it's a good idea to understand what actually happens though to understand why the standard has that requirement.
In your simple case, on a typical implementation, the memory will be freed regardless. That is because operator delete will call free(p). Since Base is the first non-virtual base class of Derived, it happens to be located at the beginning of the allocated memory block. And since free must know the size of the allocated block by its own bookkeeping (being a C function it doesn't know anything about sizes of types), it will deallocate the entire block.
However, since Base doesn't have a virtual destructor, delete p is resolved based on the static-type of *p (which is Base). Consequently, as you're seemingly aware, it will not call the destructor of Derived. If Derived had any non-trivial members or base-classes, those would not be destructed either, so any resources that they manage would be leaked.
When the class has a virtual destructor, the work of freeing the memory is delegated to the destructor. The reason is that, although free knows to determine the size of the block, it would still need to have the pointer to the beginning of it. Base can be at an arbitrary offset within Derived in the general case, therefore Derived destructor will be responsible for adjusting the pointer prior to freeing it. This also adds the need for a separate destructor that would destructor the object without actually freeing the memory; e.g. as a subobject of another derived type, or as explicit destructor call. And let's keep delete[] out of the discussion. When you mark your destructor as virtual, the compiler takes care of all this for you.
The bottom line is that the standard doesn't describe all these implementation details, leaving them instead to—um—the implementation. They could formulate some sensible criteria when deleting a non-virtual base would still be ok; but instead they went with the simple clear-cut "you have a virtual destructor then it's ok, otherwise it's not ok" rule.
Technically, the answer is 'unknown'. Deleting a pointer to derived from a pointer to base that has no virtual destructor is undefined behavior.
Practically speaking though, most implementations just fail to properly delete the stuff in the derived object.
Formally speaking, this is undefined behaviour, so you have no guarantees that the memory is freed, or indeed that your program does anything in particular. It may format your hard disk. It may not. In practice, the memory might well be freed in this case -- but you're daft if you rely on it, and you shouldn't do it. It's as simple as that.
Edit: I Was mistaken: Key prose from draft standard, emphasis mine: Section 5.3.5
3 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.
There is a good chance the memory will be correctly freed. Just because the Standard doesn't assure this doesn't mean it won't work. It's hard to see how it could fail.
In the very particular case that you describe, all of the memory used by the derived class object will be freed when you don't have a virtual destructor. (If using non-virtual destructors always caused derived classes to leak memory, I don't think the language would allow inheriting from classes that used them!)
Remember, the DESTRUCTOR is not what frees the memory; "delete" frees the memory. The destructor is just a function that gets CALLED by delete.
Blah blah blah extensibility blah blah cause yourself trouble in the future blah blah careful with that etc. etc. etc. You know what I mean, obviously.

When virtual destructor is not needed even there is a virtual function, Why?

It says that if there is a virtual function, it is a good practice to have a virtual destructor. However, if the object is created on the stack but not on heap, do we still need to do that?
Regards,
Strictly speaking no - the virtual destructor is only necessary if the object will be destroyed via a pointer to reference to a base object.
If the static type at destruction time is the actual type of the object, then the correct dtor will be called regardless of whether it's virtual or not.
But if a class has virtual functions, the reason for that is generally so that it can be accessed through a pointer or reference to one of the objects bases. If the object is going to be destroyed through that mechanism, then having a virtual dtor will ensure the correct one is called. And if you have a virtual function, making the dtor virtual comes at next to no cost.
Yes since someone else could write new code that creates your object on the heap. It would be bad practice for your class to assume that it is always going to be created on the stack...
If you write an object with a virtual method, it is expected that you will use it through an interface/base object.
And it is half-expected you will own this object through a pointer (or a smart pointer). In that last case, you need the virtual destructor.
As most of the time, your code will be used by others, you can't predict they won't use the object through its base pointer... In fact, one day, you will perhaps use it this way, too...
Now, in your case, your object is created on the stack, which means that the compiler knows its type statically. Thus, when the object will be destroyed, the right destructor will be called directly, causing zero overhead.
Conclusion: As you said, it's simple good practice, and considering the limited (or zero) cost of a virtual destructor in most cases, it should be upheld.
Simple rule:
Provide either a public virtual destructor or a protected non-virtual destructor for each class that has virtual methods.
If instances of your class are meant to be deleted through a pointer to the base then the destructor must be virtual. If you class is not meant to be deleted through base pointers then making the destructor protected will block external code from deleting through a base pointer.
Note that you can use polymorphic behavior without deleting through base pointers: when you pass the object by reference or pointer but the lifetime is handled always at the most derived type, or using constructs like shared_ptr:
class base {
protected:
~base() {}
virtual void f();
};
class derived : public base {
public:
void f();
};
int main()
{
shared_ptr<base> sp( new derived );
base *b = new derived;
//delete b; // compile time error: cannot access ~base
// if it was allowed it would be UB
delete static_cast<derived*>(b); // correct (static_cast is ok, we know the type)
} // sp goes out of scope: delete at ´derived´ level
One of the aims of OOP is code-reuse. So while you may be allocating objects on the stack at present, that may not always be the case under re-use and maintenance or in a team development environment.
It is generally a trivial overhead that significantly increases the utility, reusability and safety of your code.