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. delete
ing 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 continue
when looking at a already deleted pointer.
Related Topics
Getting an Array of Bytes Out of Windows::Storage::Streams::Ibuffer
Branchless Code That Maps Zero, Negative, and Positive to 0, 1, 2
Is Std::Ifstream Significantly Slower Than File
Generic Way to Print Out Variable Name in C++
What Does This C Code Do [Duff's Device]
C++ - How to Find the Length of an Integer
Are C++ Libs Created with Different Versions of Visual Studio Compatible with Each Other
What Is the Purpose of Ref-Qualified Member Functions
Why Isn't Rvo Applied to Base Class Subobject Initialization
Why Sizeof Built in Types Except Char Is Compiler Dependent in C & C++
Std::Vector Reserve() and Push_Back() Is Faster Than Resize() and Array Index, Why
Conversion from Boost::Shared_Ptr to Std::Shared_Ptr
Should I Use Public or Private Variables
C++ Template Class; Function with Arbitrary Container Type, How to Define It
How to Prevent an Object Being Created on the Heap