Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从构造函数抛出后调用析构函数 我曾经认为C++中,如果构造函数抛出异常,这个“部分构造”类的析构函数不被调用。_C++_Exception_C++11 - Fatal编程技术网

从构造函数抛出后调用析构函数 我曾经认为C++中,如果构造函数抛出异常,这个“部分构造”类的析构函数不被调用。

从构造函数抛出后调用析构函数 我曾经认为C++中,如果构造函数抛出异常,这个“部分构造”类的析构函数不被调用。,c++,exception,c++11,C++,Exception,C++11,但在C++11中似乎不再如此:我用g++编译了以下代码,它将“X析构函数””打印到控制台。为什么会这样 #include <exception> #include <iostream> #include <stdexcept> using namespace std; class X { public: X() : X(10) { throw runtime_error("Exception thrown in X::X()"

但在C++11中似乎不再如此:我用g++编译了以下代码,它将“
X析构函数”
”打印到控制台。为什么会这样

#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;
    }
}

委托构造函数确实是引入了新的销毁逻辑的一个新特性

让我们重温对象的生命周期:当某个构造函数完成时,对象的生命周期开始。(参见15.2/2。标准称之为“主体构造函数”。)在您的例子中,这是构造函数
X(int)
。第二个,委托构造函数
X()
现在只是一个普通的成员函数。范围展开时,将调用所有完全构造的对象的析构函数,这包括
x

这实际上意味着非常深刻:您现在可以将“复杂”的工作负载放入构造函数,并充分利用通常的异常传播,只要将构造函数委托给另一个构造函数即可。这样的设计可以消除对各种“init”函数的需求,这些函数在不需要为常规构造函数投入太多工作的情况下曾经很流行

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

[C++11:15.2/2]:
[…]类似地,如果对象的非委托构造函数 已完成执行,并且该对象的委托构造函数退出,但出现异常时,将调用该对象的析构函数。[……]

我曾经认为C++中,如果构造函数抛出异常,这个“部分构造”类的析构函数不被调用。 但在C++11中似乎不再是这样了

这仍然是事实。自C++03以来未发生任何更改(对于某些值为Nothing;-))

您的想法仍然正确,但在抛出异常时,没有部分构造的对象

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

部分构造或部分销毁的对象将对其所有完全构造的子对象执行析构函数,即,对于构造函数已完成执行而析构函数尚未开始执行的子对象。

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

基本上相同的规则适用于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类
{
公众:
X(INTA)
{

cout@Nawaz:“基本概念-对象生命周期”?@KerrekSB:在轨道删除的答案中添加了Lightness\u Races\u的引述。-)这是一个显示结果的例子,奇怪的是,这个答案只得到了一张赞成票。尽管Kerrek提到了为什么会有这个功能,但我认为这个功能在回答实际问题方面做得更好。@Tibo,是的,我也这么认为;-)我参加聚会迟到了,我认为Kerrek的当我写我的答案时,答案已经被接受了。