Does Delete on a Pointer to a Subclass Call the Base Class Destructor

Does delete on a pointer to a subclass call the base class destructor?

The destructor of A will run when its lifetime is over. If you want its memory to be freed and the destructor run, you have to delete it if it was allocated on the heap. If it was allocated on the stack this happens automatically (i.e. when it goes out of scope; see RAII). If it is a member of a class (not a pointer, but a full member), then this will happen when the containing object is destroyed.

class A
{
char *someHeapMemory;
public:
A() : someHeapMemory(new char[1000]) {}
~A() { delete[] someHeapMemory; }
};

class B
{
A* APtr;
public:
B() : APtr(new A()) {}
~B() { delete APtr; }
};

class C
{
A Amember;
public:
C() : Amember() {}
~C() {} // A is freed / destructed automatically.
};

int main()
{
B* BPtr = new B();
delete BPtr; // Calls ~B() which calls ~A()
C *CPtr = new C();
delete CPtr;
B b;
C c;
} // b and c are freed/destructed automatically

In the above example, every delete and delete[] is needed. And no delete is needed (or indeed able to be used) where I did not use it.

auto_ptr, unique_ptr and shared_ptr etc... are great for making this lifetime management much easier:

class A
{
shared_array<char> someHeapMemory;
public:
A() : someHeapMemory(new char[1000]) {}
~A() { } // someHeapMemory is delete[]d automatically
};

class B
{
shared_ptr<A> APtr;
public:
B() : APtr(new A()) {}
~B() { } // APtr is deleted automatically
};

int main()
{
shared_ptr<B> BPtr = new B();
} // BPtr is deleted automatically

Does delete work with pointers to base class?

Yes, it will work, if and only if the base class destructor is virtual, which you have done for the Base base class but not for the IFoo base class. If the base class destructor is virtual, then when you call operator delete on the base class pointer, it uses dynamic dispatch to figure out how to delete the object by looking up the derived class destructor in the virtual function table.

In your case of multiple inheritance, it will only work if the base class you're deleting it through has a virtual destructor; it's ok for the other base classes to not have a virtual destructor, but only if you don't try to delete any derived objects via those other base class pointers.

If the destructor of a subclass was called, can I stop the call to the destructor of its base class?

You are correct that the B class destructor will be called if the a D instance is destructed. The call to delete ab; in the D dtor is a bug.

The other thing to consider with this code, is that because B's dtor is not virtual you cannot delete an instance of D via a B pointer.

The DTOR for D is incorrect in both cases though, and should definitely be changed. If you plan on using the hierarchy of classes polymorphically then you also must change the B DTOR to be virtual.

Will destructor delete built-in types and pointer objects?

What the spec means is that no code is run to clean up int i. It simply ceases to exist. Its memory is part of Foo and whenever a Foo instance is released, then i goes with it.

For pointers the same is true, the pointer itself will simply disappear (it's really just another number), but the pointer might point at something that needs to also be released. The compiler doesn't know if that is the case, so you have to write a destructor.

This is why things like std::shared_ptr exist; they are clever pointers (aka 'smart') and the compiler does know if it points at something that needs to be released and will generate the correct code to do so. This is why you should always use smart pointers instead of 'naked' ones (like int *p).

deleting object through pointer to base without virtual destructor

Without virtual the destructor is resolved statically, based on the declared type of the pointer. The compiler sees an A1 * so delete pa1 will call the ~A1 destructor, and nothing else.

we don't have an instance of A1, so ~A1() should not be invoked as well.

B is derived from A1 so an instance of A1 exists as a subobject of every B. Otherwise A1* pa1 = new B; would not even compile.

And then, why only ~A1() is running, without ~A2()? Why does it behave like this?

Because the pointer is declared as an A1 *. That the actual object pointed to is a B does not matter since the destructor is not virtual.

The same way, if you changed the A2 inheritance to public and declared A2 *pa2 = new B; then delete pa2 would call ~A2 and nothing else.


[ EDIT ] The above attempts to answer the direct question of how the compiler resolves the destructor call. An important caveat, however, is that deleting a pointer to a derived type through the base pointer is technically UB (undefined behavior) when the destructor of the base class is not virtual. Quoting from the C++ standard 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 practice, many implementations will allow non-virtual destructors to still "work" as expected in certain simple cases, such as single inheritance between non-polymorphic types. Might even work for pointers to the first base class in a multiple inheritance case (for example, the pa1 above). But it's still UB strictly speaking, and there are cases where it's almost guaranteed to fail, such as pointers to a base class other than the first one (see an example of one such error here).

In C++ Inheritance, Derived class destructor not called when pointer object to base class is pointed to derived class

Your code has undefined behavior. The base class's destructor must be virtual for the following to have defined behavior.

Base* b = new Derived;    
delete b;

From the C++ standard:

5.3.5 Delete

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 in your case, the static type is Base, and the dynamic type is Derived. So the Base's destructor should be:

virtual ~Base() {cout << "Base Destructor\n"; }

delete on pointer (*&) to base class with virtual destructor c++

if (!cr)
continue;

will not work like you intend it to. deleteing a pointer doesn't reset it to nullptr. In your first call to ProcessAllCreatures() everything may work fine, when you call it a second time you will delete already deleted pointers, because you will never continuewhen looking at a already deleted pointer.

Base class has no destructor, but derived class does. Do I need to look for any pitfalls that DON'T relate to the heap?

Your base class has an implicit destructor. All will be fine.

A virtual base class destructor is used to allow a derived constructor to run when destructing via a pointer or reference to the base class. So in your case, this would be unsafe:

void destruct(Base &b) { b.~Base(); }
Derived d; destruct(d);

But this will be perfectly safe:

void destruct(Derived &d) { d.~Derived(); }
Derived d; destruct(d);

Will using delete with a base class pointer cause a memory leak?

Unless the base class destructor is virtual, it's undefined behaviour. See 5.3.5/4:

If the static type of the operand [of the delete operator] 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 behaviour is undefined.



Related Topics



Leave a reply



Submit