How "virtual" impact on destructor in C++? - c++

Virtual function from official explanation is:
A virtual function is a member function that you expect to be redefined in derived classes. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.
Please see the code first:
#include<iostream>
using namespace std;
class A
{
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
};
class B:public A
{
public:
B(): A(){cout << "B()" << endl;}
~B(){cout << "~B()" << endl;}
};
int main()
{
A * pt = new B;
delete pt;
}
Output is:
A()
B()
~A()
My question is:
Destructor of base class can't be inherited by derived class, so why we make destructor of base class to be virtual?
For the code above, I know this will lead to problem(here destructor of class B not called). I have searched so many articles or questions from google and stackoverflow and all of them tell me that destructor of base should be virtual but how "virtual" on destructor works? I mean that what the difference in core code level with/without "virtual" to the destructor?

delete pt; causes undefined behaviour if the destructor of A is not virtual.
The reason to make A's destructor virtual is to enable the use of delete pt; to delete a B object.
The rationale for this is that when the compiler sees delete pt;, in general, it has no way of knowing whether pt points to a B object or not, since that decision could have not been made until run-time. So you need to look up some run-time property of the object (in this case a vtable) to find out the right destructor to call.
Some other comments/answers suggest that the defined behaviour of your original code is to not call B's destructor , or something. However that is wrong. You are just seeing symptoms of undefined behaviour, which could be that or anything else.

If the destructor is marked virtual then when you call delete the destructor of the dynamic type of the object you have allocated will be called. In your example the static type of the object on the heap is A, whereas the dynamic type is B.
Since you have not marked the destructor virtual, there will be no run time dispatch and the destructor for A is called. This is wrong and should be fixed. If you are planning on using a class in a polymorphic way, make sure it's destructor is virtual, so that instances of the derived classes can release any resources they have acquired.

It can help to imagine how vtables are implemented.
A class with a virtual method has a pointer to a table of function pointers as its first element.
virtual on a method means there is an entry in the virtual function table for it.
For a method, inherited classes replace the entry when they override.
For destructors the entry is actually "how to call delete on this object". All descended classes automatically override it. It turns a call of delete base_ptr into if (base_ptr) base_ptr->vtable->deleter(base_ptr); conceptually.
Then the deleter of derived is effectively (almost) delete static_cast<derived*>(ptr); That does what a usual call to delete does, it calls the destructors in order.
Failing to do that leaves you with undefined behaviour. Often the UB is that the base class dtor is called.

If the function is not virtual, the C++ runtime will directly call the mangled function. For example, in the above code, the destructor may be mangled as _ZNK3AXXXXXXXXX (fake name). So when you call delete pt, the runtime will execute _ZNK3AXXXXXXXXX.
However, the result is different if the function is virtual. Like #Yakk said, a class with virtual functions will have a vtable, whose entries are function pointers. It may be at the top of the address space of this class, or at the bottom, depending on the implementation of class model. Any call of virtual function will look up this table. If the dtors are virtual, the function in derived class will override the corresponding entry in the table. When you call it using a pointer or reference, the C++ runtime will call the function in the table. Look at your example again. The entries of object pointed by pt have been overrode by class B, so when you call delete pt, the overrode version of dtor will be invoke. That's is the difference.

Related

If I change the destructor of one base class from non-virtual to virtual, what will happen?

I came across a base class whose destructor is non-virtual, although the base class have 1 virtual function fv(). This base class also has many subclasses. Many of those subclasses define its own fv().
I don't know the details of how the base and subclasses are used in the program. I only know the program works fine even the destructor of base class should be virtual.
I want to change the destructor of base class from non-virtual to virtual. But I'm not sure of the consequences. So, what will happen? What more do I need to do to make sure the program works fine after I change it?
Follow up:
After I changed the base class's destructor from non-virtual to virtual, the program failed one test case.
The result confuses me. Because if the destructor of base class is not virtual, then the program won't use base class polymorphicaly. Because if not, it leads to undefined behavior. For example, Base *pb = new Sub.
So, I think if I change destructor from non-virtual to virtual, it shouldn't cause any more bugs.
The virtuality of the destructor will not break anything in the existing code unless there are other problems. It may even solve some (see below). However the class may not be designed as polymorphic so adding virtual to its destructor enables it as polymorphic-able which might not be desirable. Nevertheless you should be able to safely add virtuality to the destructor and it should cause no issues on itself.
Explanation
Polymorphism allows for this:
class A
{
public:
~A() {}
};
class B : public A
{
~B() {}
int i;
};
int main()
{
A *a = new B;
delete a;
}
You can take pointer to the object of type A of the class that is in fact of type B. This is useful for example for splitting interfaces (e.g. A) and implementations (e.g. B). However what will happen on delete a;?
Part of object a of type A is destroyed. But what about the part of type B? Plus that part has resources and they need to be freed. Well that is a memory leak right there. By calling delete a; you call the destructor of type A (because a is a pointer to type A), basically you call a->~a();. Destructor of type B is never called. How to solve this?
class A :
{
public:
virtual ~A() {}
};
By adding virtual dispatch to the A's destructor (note that by declaring base destructor virtual it automatically makes all derived classes' destructors virtual even when not declared as such). Then the call to delete a; will dispatch the call of the destructor into virtual table to find the correct destructor to use (in this case of type B). That destructor will call parent destructors as usual. Neat, right?
Possible Problems
As you can see by doing this you cannot break anything per se. However there might be different issues in your design. For example there might have been a bug that "relied" on the non-virtual call of the destructor that you exposed by making it virtual, consider:
int main()
{
B *b = new B;
A *a = b;
delete a;
b->i = 10; //might work without virtual destructor, also undefined behvaiour
}
Basically object slicing, but since you did not have virtual destructor before then B part of the created object was not destroyed hence the assignment to i might work. If you made the destructor virtual then it does not exist and it will likely crash or do whatever (undefined behaviour).
Things like these might happen and in complicated code it may be hard to find. But if your destructor causes crashes after you made it virtual you likely have a bug like this somewhere in there and you had it there to begin with because as I said just making the destructor virtual cannot break anything on its own.
Have a look here,
struct Component {
int* data;
Component() { data = new int[100]; std::cout << "data allocated\n"; }
~Component() { delete[] data; std::cout << "data deleted\n"; }
};
struct Base {
virtual void f() {}
};
struct Derived : Base {
Component c;
void f() override {}
};
int main()
{
Base* b = new Derived;
delete b;
}
The output:
data allocated
but not deleted.
Conclusion
Whenever a class hierarchy has state, on the purely technical level, you want a virtual destructor all the way from the top.
It is possible that once you added that virtual destructor to your class, you triggered untested destruction logic. The sane choice here is to keep the virtual destructor you've added, and fix the logic. Otherwise, you're going to have resource and/or memory leaks in your process.
Technical Details
What's happening in the example is that, while Base has a vtable, its destructor itself isn't virtual, and that means that whenever Base::~Base() is called, it doesn't go through a vptr. In other words, it simply calls Base::Base(), and that's it.
In the main() function, a new Derived object is allocated and assigned to a variable of type Base*. When the next delete statement runs, it actually first attempts to call the destructor of the directly passed type, which is simply Base*, and then it frees the memory occupied by that object. Now, since the compiler sees that Base::~Base() isn't virtual, it doesn't attempt to go through the vptr of the object d. This means that Derived::~Derived() is never called by anyone. But since Derived::~Derived() is where the compiler generated the destruction of the Component Derived::c, that component is never destroyed either. Therefore, we never see data deleted printed.
If Base::~Base() were virtual, what would happen is that the delete d statement would go through the vptr of the object d, calling the destructor, Derived::~Derived(). That destructor, by definition, would first call Base::~Base() (this is auto-generated by the compiler), and then destroy its internal state, that is, Component c. Thus, the entire destruction process would have completed as expected.
It depends on what your code is doing, obviously.
In general terms, making the destructor of the base class virtual is only necessary if you have a usage like
Base *base = new SomeDerived;
// whatever
delete base;
Having a non-virtual destructor in Base causes the above to exhibit undefined behaviour. Making the destructor virtual eliminates the undefined behaviour.
However, if you do something like
{ // start of some block scope
Derived derived;
// whatever
}
then it is not necessary for the destructor to be virtual, since the behaviour is well defined (the destructors of Derived and its bases are invoked in reverse order of their constructors).
If changing the destructor from non-virtual to virtual causes a test case to fail, then you need to examine the test case to understand why. One possibility is that the test case relies on on some specific incantation of undefined behaviour - which means the test case is flawed, and may not succeed in different circumstances (e.g. building the program with a different compiler). Without seeing the test case (or an MCVE that is representative of it), however, I'd hesitate to claim it DOES rely on undefined behaviour
It may break some tests if someone who derived from a base class changed the ownership policy of class's resources:
struct A
{
int * data; // does not take ownership of data
A(int* d) : data(d) {}
~A() { }
};
struct B : public A // takes ownership of data
{
B(int * d) : A (d) {}
~B() { delete data; }
};
And usage:
int * t = new int(8);
{
A* a = new B(t);
delete a;
}
cout << *t << endl;
Here making the A's destructor virtual will cause UB. I don't think that such usage can be called a good practice, though.
You may "safely" add virtual to the destructor.
You may fix Undefined Behavior (UB) if equivalent of delete base is called, and then call the right destructors. If the subclass destructor is buggy, then you change UB by an other bug.
One thing that could change is the class's layout type. Adding a virtual destructor can change a class from being a standard-layout type to a non-standard-layout class. So anything were you rely on the class being a POD or standard-layout type, e.g.
memcpy or memmve classes around
pass to C functions
will be UB.
I know of exactly one case where a type is
used as a base class
has virtual functions
the destructor is not virtual
making the destructor virtual breaks things
and that is when the object conforms to an external ABI. All COM interfaces on Windows meet all four criteria. This isn't undefined behavior, but non-portable implementation-specific guarantees concerning the virtual dispatch machinery.
Regardless of your OS, it boils down to "The One-Definition Rule". You can't modify a type unless you recompile every piece of code using it against the new definition.

Understanding virtual destructors

I was trying to familiarize myself with the OOP concepts but could not quite understand the concept of virtual.
One can create a virtual destructor but not a virtual constructor. Why?
How are virtual destructors handled internally? I mean the link Virtual Destructors illustrates the concept but my question is how the vptr of both the vtables (Derived and Base) are called? (In case of virtual member functions when such a scenario occurs generally the function that vptr of Derived class points to is only called)
Are there any other scenarios where one may need to use a virtual destructor?
Can anyone please help me understand the above concepts with links/examples?
First, a little about the difference between virtual functions and non-virtual functions:
Every non-virtual function-call that you have in your code can be resolved during compilation or linkage.
By resolved, we mean that the address of the function can be computed by the compiler or the linker.
So in the object code created, the function-call can be replaced with an op-code for jumping to the address of that function in memory.
With virtual functions, you have the ability to invoke functions which can be resolved only during runtime.
Instead of explaining it, let's run through a simple scenario:
class Animal
{
virtual void Eat(int amount) = 0;
};
class Lion : public Animal
{
virtual void Eat(int amount) { ... }
};
class Tiger : public Animal
{
virtual void Eat(int amount) { ... }
};
class Tigon : public Animal
{
virtual void Eat(int amount) { ... }
};
class Liger : public Animal
{
virtual void Eat(int amount) { ... }
};
void Safari(Animal* animals[], int numOfAnimals, int amount)
{
for (int i=0; i<numOfAnimals; i++)
animals[i]->Eat(amount);
// A different function may execute at each iteration
}
As you can probably understand, the Safari function allows you to be flexible and feed different animals.
But since the exact type of each animal is not known until runtime, so is the exact Eat function to be called.
The constructor of a class cannot be virtual because:
Calling a virtual function of an object is performed through the V-Table of the object's class.
Every object holds a pointer to the V-Table of its class, but this pointer is initialized only at runtime, when the object is created.
In other words, this pointer is initialized only when the constructor is called, and therefore the constructor itself cannot be virtual.
Besides that, there is no sense for the constructor to be virtual in the first place.
The idea behind virtual functions is that you can call them without knowing the exact type of the object with which they are called.
When you create an object (i.e., when you implicitly call a constructor), you know exactly what type of object you are creating, so you have no need for this mechanism.
The destructor of a base-class has to be virtual because:
When you statically allocate an object whose class inherits from the base-class, then at the end of the function (if the object is local) or the program (if the object is global), the destructor of the class is automatically invoked, and in turn, invokes the destructor of the base-class.
In this case, there is no meaning to the fact that the destructor is virtual.
On the other hand, when you dynamically allocate (new) an object whose class inherits from the base-class, then you need to dynamically deallocate (delete) it at some later point in the execution of the program.
The delete operator takes a pointer to the object, where the pointer's type may be the base-class itself.
In such case, if the destructor is virtual, then the delete operator invokes the destructor of the class, which in turn invokes the destructor of the base-class.
But if the destructor is not virtual, then the delete operator invokes the destructor of the base-class, and the destructor of the actual class is never invoked.
Consider the following example:
class A
{
A() {...}
~A() {...}
};
class B: public A
{
B() {...}
~B() {...}
};
void func()
{
A* b = new B(); // must invoke the destructor of class 'B' at some later point
...
delete b; // the destructor of class 'B' is never invoked
}
One can create a virtual destructor but not a virtual constructor. Why?
Virtual functions are dispatched according to the type of the object they're called on. When a constructor is called, there is no object - it's the constructor's job to create one. Without an object, there's no possibility of virtual dispatch, so the constructor can't be virtual.
How are virtual destructors handled internally?
The internal details of virtual dispatch are implementation-defined; the language doesn't specify the implementation, only the behaviour. Typically, the destructor is called via a vtable just like any virtual function.
how the vptr of both the vtables (Derived and Base) are called?
Only the most-derived destructor will be called virtually. All destructors, virtual or not, will implicitly call the destructors of all member and direct base-class subobjects. (The situation is slightly more complicated in the presence of virtual inheritance; but that's beyond the scope of this question).
Are there any other scenarios where one may need to use a virtual destructor?
You need one in order to support polymorphic deletion; that is, to be able to delete an object of derived type via a pointer to a base type. Without a virtual destructor for the base type, that's not allowed, and will give undefined behaviour.
because a Virtual function is invoked at runtime phase, however constructors are invoked at initialization phase, object is not constructed. So it's meaningless to have a virtual constructor.
a. the reason why only the base class desctructor is invoked in your link, the destructor is not marked as virtual, so the desctructor address is linked to Base class destructor at compile/link time, and obviously the type of the pointer is Base instead of Derived at compile time.
b. for why both of Base and Derived constructors are invoked after adding virtual to Base desctructor. It's same behavior like below:
Derived d; // when d exits the lifecycle, both Derived and Base's desctructor will be invoked.
Suppose when you have at least one virtual function, you should have a virtual desctructor.
One can create a virtual destructor but not a virtual constructor.
Why?
I'll try and explain this in layman's terms.
A class in c++ only exists after it's constructor completes. Each base class exists prior to initialisation of derived class and its members (vtable links included). Hence, having a virtual constructor does not make sense (since to construct, you need to know the type). Furthermore (in c++), calling virtual functions from a constructor does not work (as the derived class's vtable part has not been set up). If one thinks about it carefully, allowing virtual functions to be called from a contructor opens up a can of worms (such as what if virtual functions of derived classes are called prior to member initialization).
As far as destructors are concerned, at the point of destruction, the vtable is "intact", and we (c++ runtime) are fully aware of the type (so to speak). The destructor of the most derived part of the type is found (if virtual, through vtable), and therefore that destructor, and naturally that of all bases can be called.
How are virtual destructors handled internally? I mean the link
Virtual Destructors illustrates the concept but my question is how the
vptr of both the vtables (Derived and Base) are called?
Destructors are handled the same as normal virtual functions (that is, there addresses are looked up in a vtable if they are virtual at the expense of one (perhaps 2?) extra level/s of indirection). Furthermore, c++ guarantees that all base destructors shall execute (in opposite order of construction which relies on order of declaration) after completion of a derived destructor.
One can mimick/simulate virtual construction by using patterns such as the prototype pattern (or cloning), or by using factories. In such cases either an instance of the real type exists (to be used polymorphically), or a factory exists (deriving from abstract factory), that creates a type (via virtual function) based on some knowledge provided.
Hope this helps.
I assume we have a Base class A, and it's derived B.
1.: You can delete B via an A pointer, and then the correct method is to call the B destructor too.
However, you just can't say, that a B object should be created while you actually just call the A constructor. There is just not such a case.
You can say:
A* a = new B ();
or
B b;
But both directly call the B's constructor.
2.: Well, i am not entirely sure, but i guess it will iterate through the relevant part of the class hierarchy, and search for the closest call of the function. If a function is not virtual, it stop iterating and call it.
3.: You should always use virtual destructor, if you want to inherit something from that class. If it's a final class, you shouldn't.
I wasted a couple of days trying to discover why my derived virtual destructors were not being called before discovering the answer so hopefully I can save other a lot of grief with this reply.
I started using derived classes three and four levels deep in my project. Virtual functions seemed to work fine but then I discovered I had massive memory leaks because my destructors were not being called. No compiler or runtime error - the destructors just were not being called.
There is a ton of documentation and examples about this on the web but none of it was useful because my syntax was correct.
I decided that if the compiler wasn't going to call my destructors, I needed to create my own virtual destruct method to call. Then I got the compiler error that solved the problem - "class if a Forward Reference". Adding an include for the derived class header files in the base class solved the problem. The compiler needs the class definition to call the destructor!
I suggest when creating a new derived class, include the header file in the base and intermediate classes. Probably also a good idea to add conditional debug code to your destructors to check that they are bing called.
Bob Rice

Why in destructors is the virtual table set back to that level?

Following this question - Pure virtual call in destructor of most derived class - I tried some code to check some syntax and discovered that as sucessive destructors are called, they call their relevant virtual functions. Consider this code:
class Base
{
public:
virtual void Method() = 0;
};
class Derived : public Base
{
public:
~Derived()
{
Method();
}
virtual void Method()
{
cout << "D";
}
};
class DoubleD : public Derived
{
public:
~DoubleD()
{
Method();
}
virtual void Method()
{
cout << "DD";
}
};
int main(array<System::String ^> ^args)
{
DoubleD D;
DoubleD E;
return 0;
}
As expected, as the object gets destructed, it calls the correct method (eg first the most derived and then the the second most derived).
Ouput: DD D
My question is, why does this work? Since you are not meant to call virtual functions in a c'tor/d'tor, why does the virtual table "unwind" correctly.
Eg, I can see why the most derived one works, that was the state the virtual function pointer table was in when this started. But why, when Derived's destructor is called, does the table get correctly set to point at that classes implementation of Method.
Why not just leave it, or if it is being nice, set the value to NULL.
Since you are not meant to call virtual functions in a c'tor/d'tor,
why does the virtual table "unwind" correctly.
The premise is wrong. There's nothing wrong with calling virtual functions from a constructor or destructor, provided you know how they work. As you've seen, the dynamic type is the type of the constructor or destructor being run, so you don't get virtual calls to the parts of the object that haven't yet been constructed or have already been destroyed.
The behaviour is perfectly well defined. You shouldn't worry about how your compiler vendor managed to implement it (though it's not very hard to reason out yourself, or just look up).
It's generally not advised to call virtual functions in the destructor because of the non-intuitive behaviour, but there's nothing fundamentally wrong with it.
This is how it is supposed to work according to the standard.
As for why, after you've run the destructor for a derived class you can't count on any of the properties of that class to be valid or consistent. Calling one of the virtual methods at that point would be a disaster if it went into a derived class method.
It's quite likely that the compiler bypasses the vtable altogether, since it already knows which overridden method applies to the current state of the object. That's just an implementation detail though.
Virtual table doesn't get modified at run time after the initial setup at object creation.
On some implementations, Virtual table shall be created as per class basis.
In your example, when DoubleD object is destroyed, it calls method function in DoubleD class, Because, the DoubleD part of the object is not yet destroyed completely.
VTable of DoubleD class has an entry for method function to point to method in its class as it is overridden(in the last level of inheritance)
Once DoubleD is destroyed, now the object type is of type Derived. So the call has to go to the method in vtable of class Derived. Hence the behavior.

How Does Virtual Destructor work in C++

I will type an example :
class A
{
public:
virtual ~A(){}
};
class B: public A
{
public:
~B()
{
}
};
int main(void)
{
A * a = new B;
delete a;
return 0;
}
Now in Above Example , destructors will be called recursively bottom to up .
My Question is how Compiler do this MAGIC .
There are two different pieces of magic in your question. The first one is how does the compiler call the final overrider for the destructor and the second one is how does it then call all the other destructors in order.
Disclaimer: The standard does not mandate any particular way of performing this operations, it only mandates what the behavior of the operations at a higher level are. These are implementation details that are common to various implementations, but not mandated by the standard.
How does the compiler dispatch to the final overrider?
The first answer is the simple one, the same dynamic dispatch mechanism that is used for other virtual functions is used for destructors. To refresh it, each object stores a pointer (vptr) to each of its vtables (in the event of multiple inheritance there can be more than one), when the compiler sees a call to any virtual function, it follows the vptr of the static type of the pointer to find the vtable and then uses the pointer in that table to forward the call. In most cases the call can be directly dispatched, in others (multiple inheritance) it calls some intermediate code (thunk) that fixes the this pointer to refer to the type of the final overrider for that function.
How does the compiler then call the base destructors?
The process of destructing an object takes more operations than those you write inside the body of the destructor. When the compiler generates the code for the destructor, it adds extra code both before and after the user defined code.
Before the first line of a user defined destructor is called, the compiler injects code that will make the type of the object be that of the destructor being called. That is, right before ~derived is entered, the compiler adds code that will modify the vptr to refer to the vtable of derived, so that effectively, the runtime type of the object becomes derived (*).
After the last line of your user defined code, the compiler injects calls to the member destructors as well as base destructor(s). This is performed disabling dynamic dispatch, which means that it will no longer come all the way down to the just executed destructor. It is the equivalent of adding this->~mybase(); for each base of the object (in reverse order of declaration of the bases) at the end of the destructor.
With virtual inheritance, things get a bit more complex, but overall they follow this pattern.
EDIT (forgot the (*)):
(*) The standard mandates in §12/3:
When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructor’s own class or in one of its bases, but not a function overriding it in a class derived from the con- structor or destructor’s class, or overriding it in one of the other base classes of the most derived object.
That requirement implies that the runtime type of the object is that of the class being constructed/destructed at this time, even if the original object that is being constructed/destructed is of a derived type. A simple test to verify this implementation can be:
struct base {
virtual ~base() { f(); }
virtual void f() { std::cout << "base"; }
};
struct derived : base {
void f() { std::cout << "derived"; }
};
int main() {
base * p = new derived;
delete p;
}
A virtual destructor is treated in the same way as any other virtual function. I note that you've correctly maked the base class's destructor as virtual. As such, it is no way different than any other virtual function, as far as dynamic dispatch is concerned. The most derived class destructor gets called through dynamic dispatch but it also automatically results in calls to Base class destructors of the class1.
Most compiler implements this feature using vtable and vptr, though the language specification does not mandate it. There can be a compiler which does this differently, without using vtable and vptr.
Anyway, as it true for most compilers, it is worth knowing what vtable is. So vtable is a table contains pointers of all virtual functions the class defines, and the compiler adds vptr to the class as hidden pointer which points to the correct vtable, so the compiler uses correct index, calculated at compile-time, to the vtable so as to dispatch the correct virtual function at runtime.
1. The italicized text is taken from #Als's comment. Thanks to him. It makes things more clear.
A suitable implementation of (virtual) destructors the compiler might use would be (in pseudocode)
class Base {
...
virtual void __destruct(bool should_delete);
...
};
void Base::__destruct(bool should_delete)
{
this->__vptr = &Base::vtable; // Base is now the most derived subobject
... your destructor code ...
members::__destruct(false); // if any, in the reverse order of declaration
base_classes::__destruct(false); // if any
if(should_delete)
operator delete(this); // this would call operator delete defined here, or inherited
}
This function gets defined even if you didn't define a destructor. Your code would just be empty in that case.
Now all derived classes would override (automatically) this virtual function:
class Der : public Base {
...
virtual void __destruct(bool should_delete);
...
};
void Der::__destruct(bool should_delete)
{
this->__vptr = &Der::vtable;
... your destructor code ...
members::__destruct(false);
Base::__destruct(false);
if(should_delete)
operator delete(this);
}
A call delete x, where x is of pointer to class type, would be translated as
x->__destruct(true);
and any other destructor call (implicit due to variable going out of scope, explicit x.~T()) would be
x.__destruct(false);
This results in
the most derived destructor always being called (for virtual destructors)
operator delete from the most derived object being called
all members' and base classes' destructors being called.
HTH. This should be understandable if you understand virtual functions.
As usual with virtual functions there will be some implementation mechanism (like a vtable pointer) that will let the compiler find which destructor to run first depending on the type of the object. Once the most derived class destructor is run it will in turn run the base class destructor and so on.
It's up to the compiler how to implement it and typically it's done with the same mechanism as other virtual methods. In other words there's nothing special about destructors that requires a virtual method dispatch mechanism that is distinct from that used by normal methods.
A virtual destructor has an entry in the virtual table just as other virtual functions do. When the destructor is invoked -either manually or automatically from a call to delete- the most derived version is invoked. A destructor also automatically calls the destructor for its base classes, so that in combination with the virtual dispatch is what causes the magic.
Unlike other virtual functions, when you override a virtual destructor, your object's virtual destructor is called in addition to any inherited virtual destructors.
Technically this can be achieved by whatever means the compiler chooses, but almost all compilers achieve this via static memory called a vtable, which permits polymorphism on functions and destructors. For each class in your source code, a static constant vtable is generated for it at compile time. When an object of type T is constructed at runtime, the object's memory is initialized with a hidden vtable pointer which points to the T's vtable in ROM. Inside the vtable is a list of member function pointers and a list of destructor function pointers. When a variable of any type that has a vtable goes out of scope or is deleted with delete or delete[], all of the destructor pointers in vtable the object points to are all invoked. (Some compilers choose to only store the most derived destructor pointer in the table, and then include a hidden invocation of the superclass's destructor in the body of every virtual destructor if one exists. This results in equivalent behavior.)
Additional magic is needed for virtual and nonvirtual multiple inheritance. Assume I am deleting a pointer p, where p is of the type of a base-class. We need to invoke the destructor of the sub-classes with this=p. But using multiple inheritance, p and the start of the derived object may not be the same! There is a fixed offset which must be applied. There is one such offset stored in the vtable for each class that is inherited, as well as a set of inherited offsets.
When you have a pointer to an object, it points to a block of memory that has both the data for that object and a 'vtable pointer.' In microsoft compilers, the vtable pointer is the first piece of data in the object. In Borland compilers, it is the last. Either way, it points to a vtable that represents a list of function vectors corresponding to the virtual methods that can be invoked for that object/class. The virtual destructor is just another vector in that list of function pointer vectors.

Who calls the Destructor of the class when operator delete is used in multiple inheritance

This question may sound too silly, however , I don't find concrete answer any where else.
With little knowledge on how late binding works and virtual keyword used in inheritance.
As in the code sample, when in case of inheritance where a base class pointer pointing to a derived class object created on heap and delete operator is used to deallocate the memory , the destructor of the of the derived and base will be called in order only when the base destructor is declared virtual function.
Now my question is :
1) When the destructor of base is not virtual, why the problem of not calling derived dtor occur only when in case of using "delete" operator , why not in the case given below:
derived drvd;
base *bPtr;
bPtr = &drvd; //DTOR called in proper order when goes out of scope.
2) When "delete" operator is used, who is reponsible to call the destructor of the class? The operator delete will have an implementation to call the DTOR ? or complier writes some extra stuff ? If the operator has the implementation then how does it looks like , [I need sample code how this would have been implemented].
3) If virtual keyword is used in this example, how does operator delete now know which DTOR to call?
Fundamentaly i want to know who calls the dtor of the class when delete is used.
<h1> Sample Code </h1>
class base
{
public:
base(){
cout<<"Base CTOR called"<<endl;
}
virtual ~base(){
cout<<"Base DTOR called"<<endl;
}
};
class derived:public base
{
public:
derived(){
cout<<"Derived CTOR called"<<endl;
}
~derived(){
cout<<"Derived DTOR called"<<endl;
}
};
I'm not sure if this is a duplicate, I couldn't find in search.
int main()
{
base *bPtr = new derived();
delete bPtr;// only when you explicitly try to delete an object
return 0;
}
This is due to tha fact that in this case the compiler know everything about the object to be destructed which in this case is drvd and is of type derived. When drvd goes out of scope the compiler inserts code to call its destructer
delete is a keyword for compiler. When compiler see delete it inserts the code to call the destructer and the code to call operator delete to deallocate the memory.Please keep in mind that keyword delete and operater delete are different.
When compiler sees keyword delete being used for a pointer it needs to generate code for its proper destruction. For this it needs to know the type information of the pointer. The only thing the compiler know about the pointer is the pointer type, not the type of object to which the pointer is pointing to. The object to which the pointer is pointing to may be a base class or a derived class. In some cases the type of object may be very clearly defined for example
void fun()
{
Base *base= new Derived();
delete base;
}
But in most cases it is not, for example this one
void deallocate(Base *base)
{
delete base;
}
So the compiler does not know which destructer to call of base or of derived. This is the way then it works
If the Base class does not have a virtual function (member function or destructer). It directly insetrts thr code to call the destructer of base class
If the Base class has virtual functions, then the compiler takes the information of destructer from vtable.
If destructer is not virtual. The vtable will have the address of base destructer and thats what will be called. This is not right since the proper destructer is not being called here. This is why it is always recommended to declare destructer of base class as virtual
If the destructer is virtual the vtable will have correcte address of destructer and compiler will insert proper code over there
+1 Good question BTW.
Look at how the virtual mechanism works for a non destructor method and you'll find a destructor behaves no differently.
There are 2 mechanism in play which may confuse the issue a little
.
Firstly a mechanism that isn't virtual is happening on construction and destruction of an object. The object is constructed from base class to derived class, in that order, and when destructed the destructor order is the reversed, so derived to based class. Nothing new here.
Consider calling a non virtual method on a based class pointer to a derived class object, what happens? The base class implementation is called. Now consider calling a virtual method from a base class pointer to a derived class object, what happens? The derived version of the method is called. Nothing you didn't already know.
Lets now consider the destructor scenario. Call delete on a base class pointer to a derived class object which has a non virtual destructor. The base class destructor is called, and if the base class had been derived from another class, then it's destructor would get called next. Because the virtual mechanism isn't in play , the derived destructor won't be called because destruction starts from the destructor you call in the hierarchy and works it way down to the base class.
Now consider the virtual destructor case. delete is called on a based class pointer to a derived class object. What happens when you call any virtual method on a base class pointer? The derived version gets called. So our derived class destructor is called . What happens during destruction, the object destructs from derived destructor to base class, but this time we started the destruction at the derived class level because of the virtual method mechanism.
Why does a stack object with either a non virtual or virtual destructor destruct from derived to base class when it goes out of scope? Because the destructor of the declared class is called in this case and the virtual mechanism has nothing to do with it.
The compiler generates all necessary code to call destructors in the right order, whether it be a stack object or member variable going out of scope, or a heap object being deleted.
You instantiate the derived type, when it goes out of scope it calls the destructor, virtual or not.
The compiler will generate code which makes a call to the destructors. It does not all happen on compile time. Code generation does, but lookin up what the address of the dtor is happens at runtime. Think about the case where you have more then 1 derived type and you do the delete using a base pointer.
A base class destructor needs to be virtual to make a polymorphic delete call the dtor of the derived type.
If you want to find out more try overloading new and delete.