【问题标题】:Why is the derived class's destructor invoked on a const reference to the base class?为什么在对基类的 const 引用上调用派生类的析构函数?
【发布时间】:2011-02-13 17:49:45
【问题描述】:

GMan's answer here 中,restore_base 类的析构函数不是virtual,所以我一直想知道它到底是如何工作的。通常,您希望 restorer_base 的析构函数仅在对象超出范围后执行,但似乎派生的 restorer_holder 析构函数确实被调用了。有大神指点一下吗?

【问题讨论】:

  • 这不值得自己提出问题。在答案下方的 cmets 中提问,@GMan 将根据需要更新答案。
  • @wilhelmtell 不,绝对可以。 const-ref 技巧非常重要,值得适当解释。
  • @Konrad Rudolph:完全同意。但是,re > 50K 的人应该重新表述问题,以便人们理解真正的问题。
  • @Martin:然后告诉我如何改写它,我会这样做,因为我真的不知道还能怎么称呼它。 :)

标签: c++ inheritance reference


【解决方案1】:

需要虚拟析构函数的标准情况是

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

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

而你的标准情况是

void foo()
{
   Derived obj;

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

GMan 的代码做了一些更棘手的事情,结果与第二种情况等价:

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

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

obj 是一个简单的引用;通常,它根本不会触发析构函数。但它是从一个匿名临时对象初始化的,该对象的静态类型(编译器已知)是Derived。当该对象 的生命周期结束时,编译器将调用Derived 析构函数。通常匿名临时对象在创建它的 表达式 结束时死亡,但临时对象初始化引用有一个特殊情况:它们一直存在到引用本身死亡,这里是范围的结束.所以你得到了伪scoped_ptr 行为,你不需要虚拟析构函数。

编辑:因为这已经出现了两次:引用不必必须是 const 才能应用此特殊规则。 C+98 [class.temporary]/5:

第二个上下文[其中一个临时对象在结束时没有被销毁 full-expression] 是当 一个引用 绑定到一个临时的。临时的 引用被绑定或临时对象的子对象的完整对象 临时绑定的对象在引用的生命周期内持续存在 ...

强调我的。这种语言中没有提到const,因此引用不必是const

编辑 2: 标准中的其他规则禁止创建对非左值临时对象的非常量引用。我怀疑至少有一些临时对象左值,但我不确定。无论如何,这不会影响此规则。对临时对象的非 const 引用在形式上仍然是正确的,即使没有严格符合的 C++ 程序可以创建这样的引用。这可能看起来很荒谬,但您应该从字面上和迂腐地阅读标准。每个单词都很重要,每个不存在的单词都很重要。

【讨论】:

  • 稍微澄清了那种延长临时生命的引用,希望大家不要介意...
  • 谢谢,现在说得通了! :) 那么对于 C++0x,是否会使用右值引用而不是 const 引用?
  • @Eugen 谢谢......但我正在查看标准(12.2p5 [class.temporary]),我没有看到任何关于必须是 const 的参考,可以你澄清你在哪里得到限制? @Xeo 我不太了解右值引用,我不知道在这种情况下它们是否合适。
  • 你完全正确,我读错了 Derived() 调用(作为函数调用并考虑了这个 herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry )。回滚了我不必要且不正确的修改。
  • error: invalid initialization of non-const reference of type ‘Base&amp;’ from an rvalue of type ‘Derived’ 我用 g++ 4.6.3 和 -std=c++98 得到了这个。我一直坚信const 是必要的。我感到很困惑:P ideone.com/rIDf4t
猜你喜欢
  • 2015-07-18
  • 2022-07-01
  • 2011-03-16
  • 2014-01-15
  • 2013-01-28
  • 1970-01-01
  • 2012-08-11
  • 1970-01-01
  • 2020-04-07
相关资源
最近更新 更多