析构函数在从构造函数中抛出后调用

我曾经认为在C ++中,如果一个构造函数抛出一个exception,那么这个“部分构造”类的析构函数就不会被调用。

但似乎在C ++ 11中是不正确的:我用g ++编译了下面的代码,并在控制台上输出“ X destructor ”。 为什么是这样?

 #include <exception> #include <iostream> #include <stdexcept> using namespace std; class X { public: X() : X(10) { throw runtime_error("Exception thrown in X::X()"); } X(int a) { cout << "X::X(" << a << ")" << endl; } ~X() { cout << "X destructor" << endl; } }; int main() { try { X x; } catch(const exception& e) { cerr << "*** ERROR: " << e.what() << endl; } } 

产量

 Standard out: X::X(10) X destructor Standard error: *** ERROR: Exception thrown in X::X() 

委托构造器确实是一个引入新的销毁逻辑的新function。

让我们重新审视一个对象的生命周期:一个对象的生命周期从一些构造函数完成时开始。 (见15.2 / 2,标准调用这个“主要构造函数”)在你的情况下,这是构造函数X(int) 。 第二,委托构造函数X()现在只是一个普通的成员函数。 范围展开后,调用所有完全构造对象的析构函数,其中包含x

这个的含义实际上是相当深刻的:只要你的构造函数委托给另一个构造函数,你现在可以把“复杂的”工作负载放到构造函数中,并充分利用通常的exception传播。 这样的devise可以避免需要各种“初始化”function,而这种function在过去不需要将过多的工作投入到常规的构造函数中时就会stream行起来。

定义您所看到的行为的特定语言是:

同样,如果对象的非委托构造函数已经完成执行,并且该对象的委托构造函数以exception退出,则会调用该对象的析构函数。 [..]

我曾经认为在C ++中,如果一个构造函数抛出一个exception,那么这个“部分构造”类的析构函数就不会被调用。

但似乎在C ++ 11中已经不是这样了

这仍然是事实。 自C ++ 03以来没有任何改变(对于一些没有任何价值的东西;-))

你认为什么是真的,但是抛出exception时没有部分构造的对象

C ++ 03 TC1标准说(强调我的):

部分构build或部分销毁的对象将为所有完全构造的子对象执行析构函数,也就是说,对于构造函数已经完成并且析构函数尚未开始执行的子对象。

即任何已经完成其构造函数的对象都将通过执行析构函数而被销毁。 这是一个很好的简单规则。

在C ++ 11中,基本上同样的规则是适用的:一旦X(int)返回,对象的“构造函数已经完成执行”,所以它是完全构造的,所以它的析构函数会在适当的时候运行范围或者是在build造后期阶段抛出的例外)。从本质上讲,这仍然是一个相同的规则。

委托构造函数的主体运行在另一个构造函数之后,可以做额外的工作,但是这并没有改变对象构造完成的事实,所以它是完全构造的。 委托构造函数类似于派生类的构造函数,它在基类的构造函数完成后执行更多的代码。 从某种意义上说,你可以认为你的例子是这样的:

 class X { public: X(int a) { cout << "X::X(" << a << ")" << endl; } ~X() { cout << "X destructor" << endl; } }; class X_delegating : X { public: X_delegating() : X(10) { throw runtime_error("Exception thrown in X::X()"); } }; 

它不是这样的,只有一个types,但是它与X(int)构造函数运行的类似,然后在委托构造函数中运行额外的代码,如果抛出X “基类”(不是真的是一个基类)被破坏。