0

Just out of curiosity I tried to do something like the example below to see if the compiler gives me a warning or so instead of calling an endless loop which ends up in a stack overflow. I thought maybe there is a different behavior than just calling normal functions or methods. But that's not the case. Is there a special explanation for that or is it just handled as normal function calls since I am explicitely calling the base class destructor by using the this operator?

Example:

class A {
  virtual ~A();
};

class B : A {
  virtual ~B() { this->~A(); }
};
Sanane Lan
  • 93
  • 1
  • 9
  • 2
    `virtual void ~A();` - this should not compile, destructors do not return anything, and normal method name cannot contain tilda. – yeputons Feb 22 '17 at 12:57
  • @yeputons right, sry, was a typo – Sanane Lan Feb 22 '17 at 12:59
  • 4
    It will cause undefined behaviour by calling `~A()` twice (since there is an implied call once `~B()`'s body exits) – M.M Feb 22 '17 at 13:00
  • @M.M so the endless loop is just a random behavior and could be anything else. – Sanane Lan Feb 22 '17 at 13:02
  • 1
    @SananeLan: Please don't type. *Copy-paste* from your local test program. – Kerrek SB Feb 22 '17 at 13:07
  • @SananeLan I think so although I wouldn't say I 100% understand the behaviour .. there might also be UB for other reasons :) Virtual dispatch is disabled in constructors and destructors – M.M Feb 22 '17 at 13:07

3 Answers3

2

@M.M's comment hit it. You are calling the destructor twice. This is undefined behavior and anything may happen, including the behavior you observe.

(In reality, most likely one of those destructor calls modifies the vptr of the object, meaning that subsequent destructor calls no longer go to the most derived object. But that's just a guess.)

The correct thing to do is to not call the destructor manually.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • 1
    C++14 [class.dtor]/15 is the clause that specifically says a second destructor call is UB, for classes with non-trivial destructor (which this is, since `virtual` makes it non-trivial) – M.M Feb 22 '17 at 13:13
1

Virtual destructors in a derived class will always call parent-class destructors first, in a recursive order such that the most "ancestral" base-class' destructor will be called, and then the second-most-"ancestral", etc. Imagine that Child inherits from Parent, which inherits from GrandParent. The Child class' destructor will actually call GrandParent's destructor, then Parent's destructor, then Child's destructor.

Indeed your derived class constructors also call their parent-class constructors in the same recursive order. You have to imagine derived classes like a "layer cake": each instance of inheritance adds a layer to your object. So the Child class has 3 layers {GrandParent, Parent, Child}, each layer's construction/destruction is handled by the corresponding class.

What you're attempting will attempt to call the parent destructor twice, which is a bad idea. Generally you do not have to explicitly call destructors, except in the case where you overloaded the new operator. See this answer for more details: Is calling destructor manually always a sign of bad design?

Community
  • 1
  • 1
Anton
  • 1,458
  • 1
  • 14
  • 28
0

Calling derived class virtual destructor causes call of base class destructor. But not vise versa.

roman
  • 103
  • 1
  • 6