析构函数从构造函数抛出后调用 [英] Destructor called after throwing from a constructor

查看:137
本文介绍了析构函数从构造函数抛出后调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我曾经认为在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆