Virtual destructor in polymorphic classes - c++

I understand that whenever you have a polymorphic base class, the base class should define a virtual destructor. So that when a base-class pointer to a derived-class object is deleted, it will call the destructor of the derived class first. Correct me if i am wrong here.
also, if the base-class destructor were to be non-virtual, it would be undefined behavior to delete a baseclass pointer to a derived object. Correct me if i am wrong aswell.
so my question is: Why is it exactly, that when the base-class destructor is non-virtual, the object will not be destroyed correctly?
i am assuming this is because virtual functions have some kind of table that is memorized and consulted whenever a virtual function is called. And the compiler knows that when an object is supposed to be deleted, it should call the derived destructor first.
is my assumption correct?

If at the point where you delete the object the static type of the variable is the bas type, than the destructor of the base type will be called, but the destructor of the sub class won't be called (as it is not virtual).
As a result the resources allocated by the base class will be freed, but the resources allocated by the sub class won't.
Thus the object won't be destructed correctly.
You are correct about that table: it is called a virtual method table or "vtable". But the result of the destructor being non-virtual is not that the destructors are not called in the correct order, but that the destructor(s) of the sub class(es) are not called at all!

Consider
struct Base {
void f() { printf("Base::f"); }
};
struct Derived : Base {
void f() { printf("Derived::f"); }
};
Base* p = new Derived;
p->f();
This prints Base::f, because Base::f is not virtual. Now do the same with destructors:
struct Base {
~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
This prints Base::~Base. Now if we make the destructor virtual, then, as with any other virtual function, the final overrider in the dynamic type of the object is called. A destructor overrides a virtual destructor in a base class (even though its "name" is different):
struct Base {
virtual ~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() override { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
The call p->~Base() actually invokes Derived::~Derived(). Since this is a destructor, after its body finishes executing, it automatically invokes destructors of bases and members. So the output is
Derived::~Derived
Base::~Base
Now, a delete-expression is in general equivalent to a destructor call followed by a call to a memory deallocation function. In this particular case, the expression
delete p;
is equivalent to
p->~Base();
::operator delete(p);
So if the destructor is virtual, this does the right thing: it calls Derived::~Derived first, which then automatically calls Base::~Base when it's done. If the destructor isn't virtual, the likely result is that only Base::~Base is invoked.

Related

No virtual functions, but still need virtual destructor?

I wrote a base and derived class that had no virtual functions. The use of virtual is typically the guide I see for when to use a virtual destructor.
However, while my classes have no virtual functions I am using the classes in a polymorphic way when I pass them around. Therefore, class Base should implement a virtual destructor?
class Base;
class Derived;
main()
{
base& baseVar = derived();
foo(baseVar);
}
There is no polymorphism because you call (will call) non-virtual functions using the referemce. That is in your example you simply call (will call) functions of the base class.
Moreover this statement
base& baseVar = derived();
should not be compiled because you bind a temporary object with a non-const reference.
There must be
const base& baseVar = derived();
As for the destructor in your example then there is no need to have a virtual destructor. Becasue you defined a reference to a temporary object of the derived class. In this case for the temporary object will be called its own destructor. That is at first the destructor of the base class will be called (from the destructor of the derived class) and then the body of the destructor of the derived class will be executed.
The vertual destructor would be need if you would allocate a derived memory in the heap and assign the address of the allocated memory to a pointer of the base class. And when you would call operator delete for this pointer then if you have no virtual destructor then the only destructor of the base class would be called.
For example
class Base;
class Derived;
main()
{
base* baseVar = new derived();
delete baseVar; // base shall have a virtual destructor
}
You should use a virtual destructor if your program will ever find itself in the position where it will be deleting an instance of a derived class through a base class pointer to ensure the correct destructor is called.
See this question for more detail When to use virtual destructors?

Override Destructor C++

From the C++ FAQ:
[11.4] Can I overload the destructor for my class?
No.
I realize this means you cannot change the return type, arguments' types nor the number of arguments. I may be splitting hairs on the syntax of the words, but is it possible to override the Parent's destructor?
class Child : public Parent {
public:
virtual Parent::~Parent() {
// New definition
}
};
And for that matter do it recursively?
class Grandchild : public Child {
public:
Child::Parent::~Parent() {
// An even newer definition
}
};
I've read this and a related post and it makes me think because destructors are not inherited, they cannot be overridden, but I've never seen it explicitly stated.
EDIT: I changed this to reflect the fact that I want to override the Parent's destructor, note Child and Grandchild overriding ~Parent().
The main reason I am doing this is to maintain Parent's interface while changing the way it is destroyed (the entire reason for the child class). I will have something else managing all Parent's created and will explicitly call their destructors at a later time of my choosing.
I may be splitting hairs on the syntax of the words
No, you are definitely not – these are two very different things.
but is it possible to override the destructor?
Yes, and in fact you must do this in many cases. In order for this to work for a polymorphic object, you need to declare the base class destructor as virtual, though:
Parent const& p = Child();
Will properly call p.~Child() at the end of scope because Parent::~Parent is virtual.
Yes, it is possible to override the destructor of a class. In fact, when you define a class hierarchy in which polymorphism is used, you must declare a virtual destructor in the base class.
Overrides of destructors work exactly the same way overrides of normal member functions work in that when you destroy an object by deleteing the object via a pointer to the base class, the destructor of the derived class is properly called. This is why you must have a virtual destructor in the base class for polymorphic hierarchies.
However, there is a difference between virtual destructors and virtual member methods which has nothing to do with the virtual nature of the destructor. That is, when executing code like this:
class A
{
public:
virtual void Foo() {}
virtual ~A() {};
};
class B : public A
{
public:
void Foo() {};
~B() {}
};
int main()
{
A* a = new B;
a->Foo(); // B::Foo() is called
delete a; // B is destroyed via B::~B()
}
...when you call a->Foo(), the method Foo() in B is called. Since B::Foo() doesn't explicitly call A::Foo(), A::Foo() isn't called.
However, when the object is destroyed via delete a;, first the destructor B::~B() is called, and then after that finishes but before control returns to the program, the base class destructor A::~A() is also called.
Of course this is obvious when you think about it, and again this has nothing to do with the virtual nature of the destructor, but it does behave differently than a normal virtual method call, so I thought I'd point it out.
Obligitory Standard Quotation:
[C++03] 12.4/6 : Destructors
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). 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).
Yes: you can have virtual destructors, and the only reason is to override them in derived classes.
It looks like this:
class Parent {
public:
virtual ~Parent();
};
class Child : public Parent {
public:
virtual ~Child();
};
class Grandchild : public Child {
public:
~Grandchild(); // virtual is inherited here
};
Note that the destructor isn't overridden by name like ordinary functions, because the name is always that of the class whose instance you're destroying.
Note also that the parent class' destructors are always called too, so you don't need to duplicate their cleanup code: read up on member object and base-class sub-object construction and destruction order for the details.
Terminology
overriding a function means implementing a base-class virtual function in a derived class. You can't change the signature at all (except for using covariant return types). So, an override always has the same signature as an inherited virtual function.
overloading a function means implementing multiple functions with the same name (and in some sense the same scope). So, an overload always has a different signature to the others with the same name, doesn't relate directly to virtual dispatch, and isn't necessarily inherited.
Yes; you can, and should, make a destructor virtual, whenever you have a child class which may be destroyed using a reference to the base class. Static code analysis tools will even complain if you don't offer a virtual destructor.
Consider the following example:
class A
{
public:
A() { a = new int; }
virtual ~A() { delete a; }
private:
int *a;
};
class B final : public A
{
public:
B() { b = new int; }
~B() { delete b; }
private:
int *b;
};
int main()
{
A *a = new B();
delete a;
}
If A's destructor was not virtual, then delete a would only call A's destructor, and you would end up with a memory leak. But because it's virtual, both destructors will be called, in the order ~B() -> ~A().

Is a derived class destructor definition required if base class destructor is virtual?

I am trying the following example:
class base // base class
{
public:
std::list<base*> values;
base(){}
void initialize(base *b) {
values.push_front(b);
}
virtual ~base()
{
values.clear();
cout<<"base called"<<endl;
}
};
class derived : public base // derived class
{
public:
~derived(){
cout<<"derived called"<<endl;
}
};
int main()
{
derived *d = new derived;
base *b = new base;
b->initialize(static_cast<base *>(d)); /* filling list */
delete b;
return 0;
}
Q.1) Why does destructor of derived class not get called, as in base class destructor I am performing values.clear()?
Q.2) Is derived class destructor definition required if base class destructor is virtual?
Q1. Because you're not deleting an object of type derived. You only do delete b;, which deletes a base. You should also call delete d;.
Also, you should specify what object is responsible for memory management. Your design is prone to error. You're better off using a smart pointer to prevent ambiguity. Also, to behave as you expect it, the destructor should be:
virtual ~base()
{
for ( int i = 0 ; i < values.size() ; i++ )
delete values[i];
values.clear();
cout<<"base called"<<endl;
}
Of course, with this approach, it would be undefined behavior calling delete d; in your main.
Q2. No, the definition is not required.
Why does destructor of derived class is not getting called, as in base class destructor I am performing values.clear();
values.clear() removes all the pointers from this list. It does not delete the objects being pointed to; that would be extremely dangerous, since the list has no way of knowing whether it's responsible for their lifetime, or whether they are just being used to refer to objects managed elsewhere.
If you want the list to own the objects, then you must either delete them yourself when removing them, or store smart pointers such as std::unique_ptr<base>. If your compiler doesn't support the new smart pointers, then you might find Boost's Pointer Container library useful.
Does derived class destructor definition is required. If base class destructor is virtual.
It's only needed if there is something in the derived class that needs cleaning up. There's no need to define an empty one if there's nothing for it to do.
You don't actually delete d, so of course the destructor is not being called. Either make d statically allocated (derived d instead of derived *d = new derived) or call delete d.
If you don't declare the destructor in the derived class a default one will be created. The base class destructor will still be called, see the FAQ (11.12). Note also that since the base class destructor is virtual, the derived class destructor is automatically virtual (whether you define one or not), see FAQ (20.7).
Why do you think the destructor of derived class should be called? You only delete base and it is an instance of the base class.
No the definition of the destructor is not required - you may ommit it.

Why base class destructor (virtual) is called when a derived class object is deleted?

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.

How do virtual destructors work?

I am using gcc. I am aware how the virtual destructors solve the problem when we destroy a derived class object pointed by a base class pointer. I want to know how do they work?
class A
{
public:
A(){cout<<"A constructor"<<endl;}
~A(){cout<<"A destructor"<<endl;}
};
class B:public A
{
public:
B(){cout<<"B constructor"<<endl;}
~B(){cout<<"B destructor"<<endl;}
};
int main()
{
A * a = new B();
delete a;
getch();
return 0;
}
When I change A's destructor to a virtual function, the problem is solved. What is the inner working for this. Why do I make A's destructor virtual. I want to know what happens to the vtable of A and B?
Virtual destructor is just a virtual function, so it adheres to the same rules.
When you call delete a, a destructor is implicitly called. If the destructor is not virtual, you get called a->~A(), because it's called as every other non-virtual function.
However if the destructor is virtual, you get ~B() called, as expected: the destructor function is virtual, so what gets called is the destructor of derived class, not base class.
Edit:
Note that the destructor of the base class will be called implicitly after the destructor of the derived class finishes. This is a difference to the usual virtual functions.
The key thing you need to know is that not using a virtual destructor in the above code is undefined behavior and that's not what you want. Virtual destructors are like any other virtual functions - when you call delete the program will decide what destructor to call right in runtime and that solves your problem.