Does Delete Work with Pointers to Base Class

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.

How is memory deallocated by delete operator with pointer to base class

Your code has undefined behavior.

It's ok to use

base* ptr = new derived();
delete ptr;

but it is not ok to use

base* ptr = new derived[10];
delete [] ptr;

Here's the relevant text from the C++11 Standard (emphasis mine):

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.

Can we perform deleting object through a pointer to one of its base classes?

"Does it cause UB if we define a virtual destructor?"

No that's just fine as the destructor was declared virtual. Stepping up the vtable and calling ~B first will be handled by delete.

Deleting a derived object via a pointer to its base class

It won't leak the object you are deleting, its memory block will be freed.

If you have not declared the destructor in base_class to be virtual then it will leak any dynamically allocated objects contained within derived_class that rely on the destructor of derived_class being called to free them. This is because if the destructor is not virtual, the derived_class destructor is not called in this case. It also means that destructors of "embedded objects" within derived_class will not automatically be called, a seperate but additional problem, which can lead to further leaks and the non-execution of vital cleanup code.

In short, declare the destructor in base_class to be virtual and you can safely use the technique you have presented.

For a coded example, see:

In what kind of situation, c++ destructor will not be called?

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).

How does delete know the size of derived class from base pointer?

delete and delete[] operators know the size of the allocation, because operators new and new[] save some housekeeping information for them at the time of allocation. It uses the same idea as malloc/free pair, when malloc saves size information that is required for free to do its job.

Figuring out the allocation size is independent of the type for which the memory is allocated. Operators delete and delete[] do not even know the type of the pointer being deleted, because they operate on void pointers.

Will delete this in a base class pointer delete the derived class object when you have a virtual destructor?

Is it going to remove the entire object or only the B and A part of the object, and leave the C part still in memory?

No. It will "do the right thing" (that is, delete the most derived subobject, run all its destructors etc.) provided A (that is, the static type of the pointee of the pointer you delete) has a virtual destructor (and if class A has a virtual destructor, all its descendants have it, too). This holds for multiple inheritance, too.

C++ deleting children basing on parent's pointer

You'll want to give A a virtual destructor (see here for why):

class A {
A();
public:
virtual ~A() = default;
};

At which point calling delete a_pointers[0] will fully destruct b_obj.

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

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.



Related Topics



Leave a reply



Submit