Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the derived class's destructor invoked on a const reference to the base class?

In GMan's answer here, the destructor of the restore_base class isn't virtual, so I keep wondering how exactly that works. Normally you'd expect the destructor of restorer_base to be executed only, after the object goes out of scope, but it seems that the derived restorer_holder destructor is really called. Anyone care to enlighten me?

like image 284
Xeo Avatar asked Feb 13 '11 17:02

Xeo


1 Answers

The standard case where you need a virtual destructor is

void foo()
{
   scoped_ptr<Base> obj = factory_returns_a_Derived();

   // ... use 'obj' here ...
}

And the standard case where you don't is

void foo()
{
   Derived obj;

   // ... use 'obj' here ...
}

GMan's code is doing something a little trickier, that turns out to be equivalent to the second case:

void foo()
{
   Base& obj = Derived();

   // ... use 'obj' here ...
}

obj is a bare reference; normally, it would not trigger destructors at all. But it's initialized from an anonymous temporary object whose static type -- known to the compiler -- is Derived. When that object's lifetime ends, the compiler will call the Derived destructor. Normally an anonymous temporary object dies at the end of the expression that created it, but there's a special case for temporaries initializing a reference: they live till the reference itself dies, which here is the end of the scope. So you get pseudo-scoped_ptr behavior and you don't need a virtual destructor.

EDIT: Since this has now come up twice: The reference does not have to be const for this special rule to apply. C+98 [class.temporary]/5:

The second context [in which a temporary object is not destroyed at the end of the full-expression] is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference ...

Emphasis mine. There is no mention of const in this language, so the reference does not have to be const.

EDIT 2: Other rules in the standard prohibit creation of non-const references to temporary objects that are not lvalues. I suspect that at least some temporary objects are lvalues, but I don't know for certain. Regardless, that does not affect this rule. It would still be formally true that non-const references to temporary objects prolong their lifetime even if no strictly conforming C++ program could ever create such a reference. This might seem ridiculous, but you're supposed to read standardese this literally and pedantically. Every word counts, every word that isn't there counts.

like image 63
zwol Avatar answered Oct 27 '22 09:10

zwol