构造函数中的异常

Exceptions in constructors

考虑以下 class:

struct A
{
    A(){ std::cout << "A()" << std::endl; throw std::exception(); }
    ~A(){ std::cout << "~A()" << std::endl; }
};

A a;
int main(){ }

DEMO

标准承诺将调用适当的释放函数N4296::5.3.4/20 [expr.new]:

If any part of the object initialization described above78 terminates by throwing an exception, storage has been obtained for the object, and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed,

但是析构函数呢?在那个例子中,它没有被调用。那么,我们得到 UB 了吗?

为所有成功初始化的对象调用析构函数。

否则必须进行默认的零初始化(一些开销)才能在析构函数中承担任何事情。

构造函数抛出异常的 A 对象未成功初始化。所以它的析构函数没有被执行。但是,如果它有任何class类型的子对象(基础class子对象,数据成员)在异常之前已经成功初始化,那么将为这些调用析构函数。

不,从构造函数中抛出不是 UB。

相反,它是发出构造失败信号的常见方式,它确保调用者要么有一个成功初始化且可能可用的对象,要么(只是)一个异常。


历史。最初 C++ 没有例外。然后通过将 0 分配给 this 来表示构造失败。我不记得它是如何与分配交互的,但大概与异常现在的交互方式相同,即有保证的释放。但是使用这个方案你只能失败动态分配对象的构造......

析构函数与释放函数不同。每当变量超出范围时,引用该变量的对象将被删除。题中你给的对象是一个全局变量,所以程序结束时会被删除