析构函数从构造函数抛出后调用 [英] Destructor called after throwing from a constructor
问题描述
我曾经认为在C ++中,如果一个构造函数抛出异常,这个部分构造类的析构函数不会被调用。
它在C ++ 11中不再是真的:我使用g ++编译了下面的代码,并将 X destructor
打印到控制台。为什么是这样?
#include< exception>
#include< iostream>
#include< stdexcept>
using namespace std;
class X
{
public:
X():X(10)
{
throw runtime_error ::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;
}
}
输出
标准输出:
X :: X(10)
X析构函数
标准错误:
***错误:X :: X()中抛出异常
让我们重温一个对象的生命周期:
对象的生命周期开始于某些构造函数完成时。 (见15.2 / 2。标准称之为主体构造函数。)在你的情况下,这是构造函数 X(int)
。第二个,委托构造函数 X()
现在作为一个普通成员函数。在范围解开时,调用所有完全构造的对象的析构函数,并且这包括 x
。 这实际上是非常深刻的:现在可以将复杂工作负载放入构造函数中,并充分利用通常的异常传播,只要将您的构造函数委派给另一个构造函数即可。这样的设计可以避免需要各种init函数,只要不希望将太多的工作放入常规构造函数中,它们就会被广泛使用。
定义您所看到的行为的特定语言是:
[C ++ 11:15.2 / 2 ]: [...] 类似地,如果对象
的非委托构造函数已完成执行并且该对象的委托构造函数退出异常,将调用对象的析构函数。 [..]
I used to think that in C++, if a constructor throws an exception, the destructor of this "partially constructed" class is not called.
But it seems that it is not true anymore in C++11: I compiled the following code with g++ and it prints "X destructor
" to the console. Why is this?
#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;
}
}
Output
Standard out:
X::X(10)
X destructor
Standard error:
*** ERROR: Exception thrown in X::X()
Delegating constuctors are indeed a new feature that introduces a new destruction logic.
Let us revisit the lifetime of an object: An object's lifetime begins when some constructor has finished. (See 15.2/2. The standard calls this the "principal constructor".) In your case, this is the constructor X(int)
. The second, delegating constructor X()
acts as just a plain member function now. Upon scope unwinding, the destructors of all fully-constructed objects are called, and this includes x
.
The implications of this are actually quite profound: You can now put "complex" work loads into a constructor and take full advantage of the usual exception propagation, as long as you make your constructor delegate to another constructor. Such a design can obviate the need for various "init"-functions that used to be popular whenever it wasn't desired to put too much work into a regular constructor.
The specific language that defines the behaviour you're seeing is:
[C++11: 15.2/2]:
[..] Similarly, if the non-delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. [..]
这篇关于析构函数从构造函数抛出后调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!