In the code below, b is a base-class pointer. However, when I invoke the destructor (either explicitly or implicitly via delete), the derived class destructor is invoked first. I don't understand how this works. There could be any number of derived classes, each with their own destructors. How can the compiler know which derived class destructor to invoke from the base destructor?
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() { cout << "Base destructor" << endl; }
};
class Derived : public Base {
public:
~Derived() { cout << "Derived destructor" << endl; }
};
int main(int argc, char * argv[]) {
Base * b = new Derived();
b->~Base(); // delete b; has the same result
}
dynamic binding, the compiler doesn't decide, the runtime does because the destructor is virtual. C++ destruction calls the destructor on the current class and implicitly calls the parent class until it hits the base class.
The call to virtual destructor works the same as a call to any other virtual function, as a result of virtual dispatch via virtual table. Apart from this,
b->~Base(); // delete b; "has the same result"
this is not true, because delete also frees the memory, which you haven't done here. delete b calls a destructor for *b and deallocates raw memory to operating system. You have only destroyed the building but haven't given ground back.
This is done the same way as virtual functions. Its called dynamic binding. When non virtual member functions are resolved statically means at compile-time, virtual members are resolved dynamically means during run time. Compiler maintains a vtable for this. If the object has one or more virtual functions, the compiler puts a hidden pointer in the object called a "virtual-pointer" or "v-pointer." This v-pointer points to a global table called the "virtual-table" or "v-table.". Read more in details from here.
It doesn't. It happens the other way around. Normal virtual function despatching calls the derived destructor, and the derived destructor calls the base destructor.
Note: My first answer was so off-base that I deleted it. It was so far off-base that someone should have down voted my response. This is another try.
In the opening post, master_latch asked:
How can the compiler know which derived class destructor to invoke from the base destructor?
How this happens is implementation specific.
Why this has to happen is "because the standard says so." Here's what the standard says:
C++11 12.4 paragraph 5:
After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant members, the destructors for X’s direct base classes and, if X is the type of the most derived class, its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed in the reverse order of the completion of their constructor. A return statement in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called. Destructors for elements of an array are called in reverse order of their construction.
C++11 12.4 paragraph 10:
In an explicit destructor call, the destructor name appears as a ~ followed by a type-name or decltype-specifier that denotes the destructor’s class type. The invocation of a destructor is subject to the usual rules for member functions, ...
The example code in C++11 12.4 paragraph 10 indicates the intent of the above:
struct B {
virtual ~B() { }
};
struct D : B {
~D() { }
};
D D_object;
B* B_ptr = &D_object;
void f() {
D_object.B::~B(); // calls B’s destructor
B_ptr->~B(); // calls D’s destructor
...
}
master_latch, your example of using b->~Base(); is identical to the second call in the example code. Think of b->~Base(); as if it meant b->__destruct_me(). It is in a sense no different than a call to any other virtual function.
A compliant implementation has to do this because "because the standard says so." How an implementation does it? The standard doesn't say. (That's good requirementese, by the way. Say what has to be done, but don't say how to do it.)
Most implementations (every implementation I have poked into) do this by generating multiple functions for a destructor. One function implements the body of the destructor as specified by the programmer. A wrapper destructor executes this body of the destructor function, then destroys non-static data members in reverse order of construction, and then invokes parent class destructors. That classes can virtually inherit from some parent class adds another twist. This means that a third destructor function for a given class might be needed.
So how does an implementation know that b->~Base() should call the wrapper destructor for class Derived? Dynamically casting a pointer to a polymorphic class to a void* pointer yields a pointer to the most derived object.
C++11 5.2.7 paragraph 7:
If T is “pointer to cv void,” then the result is a pointer to the most derived object pointed to by v. Otherwise, a run-time check is applied to see if the object pointed or referred to by v can be converted to the type pointed or referred to by T.
In other words, dynamically casting a polymorphic pointer to void* yields a pointer to the object as it was declared or allocated. The virtual table (not a part of the standard) dictates how to find the destructor. The implementation ensures that the pointer to the virtual table can be determined from a void* pointer to the most derived object. This is what lets the implementation know which destructor to call. From that point on, the pointer to that most derived object is no longer a void* pointer.
Related
I'm having trouble understanding what's the reason for the crash in the following code :
class A {
public:
virtual ~A() { goo(); }
void goo() { absFoo(); }
virtual void absFoo() = 0;
};
class B : public A {
public:
void absFoo() { cout << "In B \n"; }
};
int main()
{
B b1;
b1.goo();
}
The main prints "In B" as expected, but in the end when it crashes, I can't debug it either, the compiler pops a weird message.
So my question is, when the destructor of A calls "goo()", does "absFoo()", crash
because we're referring to an abstract function?
Or does the compiler actually look for a definition in the derived classes? (And it doesn't exist anymore because it was destructed beforehand so it crashes)
I know that if we had called "absFoo()" directly from the destructor, the reason would have been the abstract function. But since here it's an outside function calling "absFoo()" I'm having trouble understanding the real reason.
What happens when a destructor calls an abstract function
First, let us consider what happens when a destructor calls any virtual function (the same applies to the constructor by the way): When a virtual function foo is called in the destructor of T, the call will not be dispatched dynamically to an implementation in a derived type (the lifetime of any derived object has already ended), but statically to the implementation T::foo.
If T::foo is pure virtual, then calling it without dynamic dispatch will have undefined behaviour. That is what happens when a pure virtual function is (indirectly) called in a destructor (or constructor).
Just to complement the already accepted answer, this is the documentation from cppreference.
When a virtual function is called directly or indirectly from a
constructor or from a destructor (including during the construction or
destruction of the class’s non-static data members, e.g. in a member
initializer list), and the object to which the call applies is the
object under construction or destruction, the function called is the
final overrider in the constructor’s or destructor’s class and not one
overriding it in a more-derived class.
In other words, during construction or destruction, the more-derived classes do not exist.
As the object is deconstructed, the vtable is updated to match the new status of the object.
Since you've removed the last function, the compiler will do whatever it considers fit; which in the case of a debug compilation in visual studio, will fallback to an abort reporting that a pure virtual function was called.
The vtable however is not part of the standard, it's an implementation detail, and there's no requirement for your program to crash; it's just what is considered the nicest thing to do when you've called a pure virtual function.
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
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.
A difference between a destructor (of course also the constructor) and other member functions is that, if a regular member function has a body at the derived class, only the version at Derived class gets executed. Whereas in case of destructors, both derived as well as base class versions get executed?
It will be great to know what exactly happens in case of destructor (maybe virtual) & constructor, that they are called for all its base classes even if the most derived class object is deleted.
Thanks in advance!
The Standard says
After executing the body of the destructor and destroying any automatic objects allocated within the body,
a destructor for class X calls the destructors for X’s direct non-variant members,the destructors for X’s direct
base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for
X’s virtual base classes. All destructors are called as if they were referenced with a qualified name, that is,
ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed
in the reverse order of the completion of their constructor (see 12.6.2). A return statement (6.6.3) in a
destructor might not directly return to the caller; before transferring control to the caller, the destructors
for the members and bases are called. Destructors for elements of an array are called in reverse order of
their construction (see 12.6).
Also as per RAII resources need to be tied to the lifespan of suitable objects and the destructors of respective classes must be called upon to release the resources.
For example the following code leaks memory.
struct Base
{
int *p;
Base():p(new int){}
~Base(){ delete p; } //has to be virtual
};
struct Derived :Base
{
int *d;
Derived():Base(),d(new int){}
~Derived(){delete d;}
};
int main()
{
Base *base=new Derived();
//do something
delete base; //Oops!! ~Base() gets called(=>Memory Leak).
}
Constructor and destructor are different from the rest of regular methods.
Constructor
can't be virtual
in derived class you either call explicitly constructor of base class
or, in case where you don't call base class constructor compiler will insert the call. It will call the base constructor without parameters. If no such constructor exists then you get compiler error.
struct A {};
struct B : A { B() : A() {} };
// but this works as well because compiler inserts call to A():
struct B : A { B() {} };
// however this does not compile:
struct A { A(int x) {} };
struct B : A { B() {} };
// you need:
struct B : A { B() : A(4) {} };
Destructor:
when you call destructor on derived class over a pointer or a reference, where the base class has virtual destructor, the most derived destructor will be called first and then the rest of derived classes in reversed order of construction. This is to make sure that all memory has been properly cleaned. It would not work if the most derived class was called last because by that time the base class would not exists in memory and you would get segfault.
struct C
{
virtual ~C() { cout << __FUNCTION__ << endl; }
};
struct D : C
{
virtual ~D() { cout << __FUNCTION__ << endl; }
};
struct E : D
{
virtual ~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
C * o = new E();
delete o;
}
output:
~E
~D
~C
If the method in base class is marked as virtual all the inherited methods are virtual as well so even if you don't mark the destructors in D and E as virtual they will still be virtual and they still get called in the same order.
This is by design. The destructor on the base class must be called in order for it to release its resources. Rule of thumb is that a derived class should only clean up its own resources and leave the base class to clean up itself.
From C++ spec:
After executing the body of the
destructor and destroying any
automatic objects allocated within the
body, a destructor for class X calls
the destructors for X’s direct
members, the destructors for X’s
direct base classes and, if X is the
type of the most derived class
(12.6.2), its destructor calls the
destructors for X’s virtual base
classes. All destructors are called as
if they were referenced with a
qualified name, that is, ignoring any
possible virtual overriding
destructors in more derived classes.
Bases and members are destroyed in the
reverse order of the completion of
their constructor (see
12.6.2).
Also, because there is only one destructor, there is no ambiguity as to which destructor a class must call. This is not the case for constructors, where a programmer must pick which base class constructor should be called if there isn't an accessible default constructor.
Because that's how dtor's work. When you create an object, ctors are invoked starting from the base, and going all the way to the most derived. When you destroy objects (correctly) the reverse happens. The time that making a dtor virtual makes a difference is if/when you destroy an object via a pointer (or reference, though that's fairly unusual) to the base type. In that case, the alternative isn't really that only the derived dtor gets invoked -- rather, the alternative is simply undefined behavior. That make happen to take the form of invoking only the derived dtor, but it might take an entirely different form as well.
A base class destructor may be responsible for cleaning up resources that were allocated by the base class constructor.
If your base class has a default constructor (one that doesn't take parameters or has defaults for all its parameters) that constructor is automatically called upon construction of a derived instance.
If your base class has a constructor that requires parameters, you must call it manually in the initializer list of the derived class constructor.
Your base class destructor will always be automatically called upon deletion of the derived instance since destructors don't take parameters.
If you're using polymorphism and your derived instance is pointed to by a base class pointer, then the derived class destructor is only called if the base destructor is virtual.
As Igor says constructors must be called for base classes. Consider what would happen if it wouldn't be called:
struct A {
std::string s;
virtual ~A() {}
};
struct B : A {};
If the destructor for A would not be called when deleting a B instance, A would never be cleaned up.
When any object is destroyed, destructors run for all sub-objects. This includes both reuse by containment and reuse by 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.