我曾经认为在C++中,如果构造函数抛出异常,这个“部分构造的”类的析构函数就不会被调用。
但在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()
发布于 2013-01-18 03:45:11
委托构造器确实是一个引入了新的销毁逻辑的新特性。
让我们回顾一下对象的生命周期:当某个构造函数完成时,对象的生命周期就开始了。(参见15.2/2。该标准将其称为“主体构造函数”。)在本例中,这是构造函数X(int)
。第二个,委托构造函数X()
现在只是一个普通的成员函数。在作用域展开时,调用所有完全构造的对象的析构函数,这包括x
。
这实际上有很深的含义:只要将构造函数委托给另一个构造函数,就可以将“复杂”的工作负载放入构造函数中,并充分利用通常的异常传播。这样的设计可以消除对各种“初始化”-functions的需求,每当不希望在常规构造函数中投入太多工作时,这些“初始化”a就很流行。
定义你所看到的行为的特定语言是:
[C++11: 15.2/2]:
..同样,如果对象的非委托构造函数已完成执行,并且该对象的委托构造函数退出时出现异常,则将调用该对象的析构函数。..
发布于 2013-01-18 08:06:06
我曾经认为在C++中,如果构造函数抛出异常,这个“部分构造的”类的析构函数就不会被调用。
但在C++11中似乎不再是这样了
这仍然是真的。自C++03以来未做任何更改(对于某些值为Nothing ;-)
你所认为的仍然是正确的,但是当抛出异常时,没有部分构造的对象。
C++03 TC1标准说(强调我的):
部分构造或部分销毁的对象将对其所有完全构造的子对象执行析构函数,即对构造函数已完成执行但析构函数尚未开始执行的子对象执行析构函数。
也就是说,任何已经完成其构造函数的对象都将通过执行析构函数而被销毁。这是一个很好的简单规则。
从根本上讲,同样的规则也适用于C++11:一旦X(int)
返回,对象的“构造函数就完成了执行”,因此它被完全构造了,因此它的析构函数将在适当的时候运行(当它超出作用域或者在构造的后期阶段抛出异常时)。本质上,它仍然是相同的规则。
委托构造函数的主体在另一个构造函数之后运行,可以做额外的工作,但这不会改变对象的构造已经完成的事实,因此它是完全构造的。委托构造函数类似于派生类的构造函数,它在基类的构造函数完成后执行更多的代码。在某种意义上,你可以把你的例子看作是这样的:
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()");
}
};
实际上并不是这样的,只有一种类型,但在X(int)
构造函数运行时它是相似的,那么委托构造函数中的额外代码就会运行,如果这抛出了X
“基类”(实际上不是基类)就会被销毁。
https://stackoverflow.com/questions/14386840
复制相似问题