为什么派生类的析构函数在基类的const引用上调用? [英] Why is the derived class's destructor invoked on a const reference to the base class?
问题描述
在 GMan的回答, restore_base
类的析构函数不是 virtual
,所以我一直想知道它是如何工作的。通常你会期望只有在对象超出范围之后才会执行 restorer_base
的析构函数,但看起来派生的 restorer_holder
析构函数真的被调用。
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?
推荐答案
你需要一个虚拟析构函数的标准情况是
The standard case where you need a virtual destructor is
void foo()
{
scoped_ptr<Base> obj = factory_returns_a_Derived();
// ... use 'obj' here ...
}
的标准情况是
void foo()
{
Derived obj;
// ... use 'obj' here ...
}
GMan的代码做的有点棘手,原来是相当于第二种情况:
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
是一个裸参考;通常,它不会触发析构函数。但它是从一个匿名临时对象初始化的,其静态类型 - 编译器知道 - Derived
。当该对象的生命周期结束时,编译器将调用 Derived
析构函数。通常,匿名临时对象在创建它的表达式的末尾处结束,但是临时表达式初始化引用有一种特殊情况:它们活动直到引用本身死亡,这里是范围的结束。所以你得到伪 - scoped_ptr
行为,你不需要一个虚拟析构函数。
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.
由于这已经出现了两次:引用不必须要 const
才能应用此特殊规则。 C + 98 [class.temporary] / 5:
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:
第二个上下文[其中临时对象不会在
full-expression]是当引用绑定到临时时。引用绑定的
的临时或临时绑定的临时绑定的子对象的临时对象临时绑定的临时对象在引用的生命周期中保持 ...
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 ...
强调我。在这种语言中没有提到 const
,所以引用不必是 const
。
Emphasis mine. There is no mention of const
in this language, so the reference does not have to be const
.
编辑2:标准中的其他规则禁止创建对非临时对象的非const引用。我怀疑至少一些临时对象是左值,但我不知道肯定。无论如何,不影响此规则。即使没有严格符合的C ++程序可以创建这样的引用,对非临时对象的非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.
这篇关于为什么派生类的析构函数在基类的const引用上调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!