当委托构造函数抛出异常时,析构函数是否被调用?

19

众所周知,如果构造函数抛出异常,则包括成员数据和各种基类在内的所有完全构造的子对象都将以相反的顺序被销毁。但是,对于非委托构造函数,析构函数不会被调用。对于委托构造函数,当进入构造函数主体时,对象已经被构造,但是构造过程仍在继续。因此,问题是:如果委托构造函数从其主体中抛出异常,该类的析构函数是否会被调用?

class X
{
public:
    X();
    X(int) : X() { throw std::exception(); } // is ~X() implicitely called?
    ~X();
};

2
X不是X的成员对象,那么为什么会调用它的析构函数呢? - Praetorian
6
因为它已经被委派构造函数完全构建完成;而且标准规定它必须这样做。 - Mike Seymour
1
相关链接:https://dev59.com/GWYq5IYBdhLWcg3wjBUM - Jonathan Wakely
好问题,但是重复了,因此得分为-1。 - Walter
1
我真的不喜欢当一个问题被认为是重复的,即使最初的问题是以一种几乎无法通过搜索找到它的方式提出的。至少我希望那些寻找这个问题答案的人能在这里找到它。 - Ralph Tandetzky
2个回答

16
规则是对于所有已完全构造的对象都调用析构函数。一旦任何构造函数(包括委派构造函数,尽管程序继续在另一个构造函数中)完成,对象就被认为是完全构造的。

你能引用一个标准参考文献来支持这个观点吗?尽管它很符合直觉。 - Mark B
3
同样地,如果一个对象的非委托构造函数已经执行完毕,并且该对象的委托构造函数因异常而退出,则该对象的析构函数将被调用。@MarkB §15.2/2 - James Kanze
1
我不确定我喜欢那种行为。 - Martin York
1
有趣...这使得可以使用私有委托构造函数和公共委托构造函数编写两阶段构造函数,仅用于异常安全问题。我想知道它是否能提供任何真正的优势。 - rodrigo
2
@LokiAstari,除此之外都没有意义(尽管我能理解你的担忧)。非委托构造函数已将类置于定义状态(并可能分配需要释放的资源),因此必须调用析构函数。在委托构造函数中,构造函数体中的代码处于某种悬空状态:它在构造函数中,但不是类的主要构造的一部分。 - James Kanze
显示剩余5条评论

7
任何构造函数(即在委派的情况下,最终目标构造函数)成功完成时,对象的生命周期开始。根据[C++03] §3.8的规定,“构造函数调用已完成”表示任何构造函数调用。这意味着从委托构造函数主体引发的异常将自动调用析构函数。
参考来源:source
如果有人想阅读有关委派构造函数的文章,请点击此处

1
除非您引用的源是该功能的早期提案。您引用的确切词语并没有被纳入最终标准,或者至少我找不到它们。而您引用的“好文章”更多地涉及在没有委托构造函数时该怎么做。 - James Kanze
如果委托构造函数在非委托构造函数成功完成后退出并引发异常,则会调用该对象的析构函数。 - Kristian Spangsege

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接