I have Y-shaped class hierarchy: class C inherits from A and B, and class D inherits from C. A and B have virtual destructors and C's destructor is not virtual. I know that if there is no double inheritance (say no B) ~C() will be virtual. My question is does double inheritance affects it?
class A { virtual ~A(); ...};
class B { virtual ~B(); ...};
class C : public A, public B { ~C(); ...};
class D : public C { virtual ~D(); ... };
I have to delete instances of class D through a pointer to C.
C* c = new D;
delete c;
I suspect that there are some corner cases where ~B() is not executed - is it possible? Can it depend upon level of optimizations? Should definition of to D present in .cc file where 'delete c' is called?
All destructors except ~B() are nops, class C is empty class: no data members, no functions, just a trivial constructor and an empty destructor. I wrote several test programs in all cases ~B() was executed, but I am sure I did not try all the possible combinations.
C destructor is implicitly virtual since at least one of its base destructor is virtual.
Thus because C destructor is virtual and you delete through a pointer to C, D destructor would be called.
If neither A or B destructor would be virtual, then it would be undefined behavior to delete a D object but this is not the case here.
If a class C derive from class(es), then it knows how to destroy its base classes. Thus B destructor would always be called (assuming that you delete either the final object or from a level where the destructor is virtual either explicitly or implicitly.
In practice, even in the undefined case (only D destructor is virtual and object is deleted through C pointer), B destructor would probably have been called but D part would not have been properly destroyed. But since, it is undefined, you cannot rely on that.
C's destructor is not virtual.
Yes it is. It has base(s) with a virtual destructor(s), so the destructor of C is implicitly virtual. Whether the destructor is declared virtual explicitly or not is irrelevant. Same goes for destructor of D.
I have to delete instances of class D through a pointer to C.
I suspect that there are some corner cases where ~B() is not executed - is it possible?
As long as C's destructor is virtual, there is no problem. If C's destructor wasn't virtual, then deleting a dervied object through a pointer to C would have undefined behaviour.
As far as I know, destructor chaining has nothing to do with virtual destructor. As long as destructor of certain class is invoked, it will automatically invoke the base class desctructors for you.
What Virtual-ness of Desctructor come into picture is when you are deleting a derived class instance through a pointer of base class.
In your above example, assuming ~C is not virtual (i.e. you are not declaring virtual for any destructor), and if you are deleting a D instance through a C*, desctructor of D could have been missed, and compiler is going to call ~C for you instead. As mentioned above, calling ~C is going to cause all base class destrcutors (~A & ~B) to be called automatically.
However, given you have already declared destructor to be virtual in base class (A etc), virtual-ness will propagate to all derived classes' destructor. Which means, even you have not declared ~C as virtual, it is actually virtual.
Related
When virtual class B derives from a virtual base class A, unless explicitly declaring a virtual destructor in A and B, B's destructor in the vtable will point to A's destructor. Why? Why doesn't the B's vtable destructor point on B's destructor automatically without having to define A and B virtual destructors?
edit: realized that without making A's destructor virtual, B's destructor isn't even in the vtable so when calling A's destructor it justs direct calls A's. My question doesn't make sense.
C++ works on the principle of "you don't pay for what you don't use". Forcing the destructor of any class that has any virtual function to be virtual, even if the clients of the class never delete objects of that class polymorphically (i.e. through a base pointer), is a non-zero cost (slot in the vtable, deletes on the object needing a virtual function call). Therefore, C++ doesn't do that without explicit instruction.
I have a base class A with a virtual destructor. A has descendants B and C which use the default destructor. Is it safe to delete an object of C through a pointer to A?
More specifically, consider this sample code:
class A {
public:
A(){};
virtual ~A() {/* code here */};
};
class B: public A {
B() {/* code....*/};
/* NO DESTRUCTOR SPECIFIED */
};
class C: public B {/*same as above, no destructor */};
class D: public B {/* same as above, no destructor*/}
The code to be run looks something like this:
A* getAPointer(void); /* a function returning a C or a D*/
A* aptr=getAPointer();
/* aptr is declared as A*, but points to either an object of class C
or class D*/
delete aptr;
Is the delete aptr safe? Does it do the right thing: if aptr points to an object of class C, the aptr first calls C's destructor, then B's destructor, and finally A's destructor ?
Is it safe to delete an object of C through a pointer to A?
Yes, it is totally safe as all the destructors in classes B, C and D will be implicitly virtual.
From:
15.4 Destructors [class.dtor]
10 A destructor can be declared virtual (13.3) or pure virtual (13.4);
if any objects of that class or any derived class are created in the
program, the destructor shall be defined. If a class has a base class
with a virtual destructor, its destructor (whether user- or
implicitly-declared) is virtual.
As A has a virtual destructor, then B, and C, D respectively, have virtual destructors and:
delete aptr;
works correctly.
Yes, it's safe. Adding virtual to the destructors of your derived classes is redundant.
Consider how the mechanism works. When delete is used, the runtime needs to know with which destructor the destruction chain should begin. If the static type of the delete operand has a virtual destructor, then that's already sufficient for the runtime to know that it must take the extra trouble and inspect the dynamic type.
In your case, it finds that the dynamic type is C, so C::~C is called. C::~C automatically leads to B::~B and that one automatically leads to A::~A.
A requirement for C's (or B's) destructor to be virtual would be pointless. After all, the runtime has to find out the dynamic C type anyway if A::~A is virtual. At that point, it doesn't care whether C::~C is virtual or not. What difference would it make?
Is it safe to delete an object of C through a pointer to A?
Yes. Since A's destructor is virtual, C's destructor will be called. This is simply due to how dynamic dispatch works.
Do C++ destructors need to be defined as virtual? If so why? I've read that they need to be to ensure proper clean-up when one casts a base class pointer to a derived class.
A virtual destructor is required to allow dynamic dispatch of the destructor call to the proper class in the hierarchy tree.
In a situation in which you have:
Base *d = new Derived();
delete d;
without a virtual destructor you have undefined behavior. This because the compiler is not able to find the most specialized destructor for Derived, since it's not declared as virtual.
It is not required formally - you can easily compile a class with virtual functions but not a virtual destructor, but that's unwise.
Imagine you have a base class A, and two derived classes B and C. B and C have different fields and need different cleanup in destructor.
Now you assign
A *p = new B();
Then, when you call
delete p;
The compiler wouldn't know which destructor to call (actually this is an undefined behaviour according to the C++ standard).
If you don't define a virtual destructor, only the destructor of A could be called, which is not sufficient in the case of our hypothetical class B.
If you never instantiate your class with a new keyword (and afterwards delete it) you don't need a virtual destructor. However, adding a virtual destructor doesn't affect the performance, so it's best to always provide it.
in C++: Why should the destructor of base classes be virtual?
The better question is when and why. Your question indicates that you think all base classes should have virtual destructors, which is not quite true.
It would make it impossible to apply the empty base class optimization, and could multiply the size of classes up to 16 times than what it would be without virtual on common platforms.
A virtual destructor is needed when you delete an object whose dynamic type is DerivedClass by a pointer that has type BaseClass*. The virtual makes the compiler associate information in the object making it able to execute the derived class destructor. Missing the virtual in such case causes undefined behavior.
If you don't need this, and your class is only used as a base class, it's best to make the destructor protected, thus preventing that users accidentally delete in the described way.
You want them to be virtual so that all subclass destructors are automatically called when the object is destroyed, even if it is destroyed through a pointer to the base class. In the following code:
class base {
public:
virtual ~base() { }
};
class derived : public base {
public:
~derived() { } // Inherits the virtual designation
};
int main(void)
{
base *b = new derived;
delete b;
}
The derived destructor will only be called if the base destructor is virtual.
As Magnus indicates, you don't have to do this if you aren't taking advantage of polymorphism. However, I try to develop the habit of declaring all my destructors virtual. It protects me against the case where I should have declared them virtual but forget to do so. As Johannes indicates, this habit can impose a small space and performance penalty when the virtual designation is not needed.
They dont have to be virtual unless you are using polymorphism. If you do use polymorphism they need to be virtual so that the destructors of inherited classes are guaranteed to be called, so inherited classes can do their clean up.
For situations like this:
class A
{
virtual ~A();
};
class B:A
{
~B();
};
A *a = new B(); //legal, since it's a downcast
delete a; //Unless the destructor is virtual, ~A() is called here instead of ~B().
It should be virtual to ensure that the destructor of the inherited classes are the ones actually getting called at runtime instead of the base class destructor being called.
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.