C ++标准是否保证统一初始化是异常安全的?

时间:2017-04-28 12:15:21

标签: c++ exception gcc c++17 uniform-initialization

#include <iostream>

using namespace std;

struct A
{
    A() { cout << "A" << endl; }
    ~A() { cout << "~A" << endl; }
};

A Ok() { return {}; }
A NotOk() { throw "NotOk"; }

struct B
{
    A a1;
    A a2;
};

void f(B) {}

int main()
{
    try
    {
        f({ Ok(), NotOk() });
    }
    catch (...)
    {}
}

vc++clang输出:

A
~A

虽然gcc输出:

A

这似乎是海湾合作委员会的一个严重错误。

如需参考,请参阅GCC bug 66139"A serious bug in GCC" by Andrzej Krzemieński

我只是想知道:

C ++标准是否保证统一初始化是异常安全的?

1 个答案:

答案 0 :(得分:31)

似乎如此:

奇怪地在所有地方的§6.6/ 2跳跃声明[stmt.jump]中找到(N4618):

  

退出范围(无论多么已完成),具有自动对象   在该范围内构建的存储持续时间(3.7.3)   按其建造的相反顺序销毁。 [注意:为   临时的,见12.2。 -end note]转出一个循环,出一个   使用自动存储功能阻止或返回已初始化的变量   持续时间涉及使用自动存储破坏对象   在转移点但不在转移点的范围内的持续时间   转移到的点。 (转入块中见6.7)。 [ 注意:   但是,程序可以终止(通过调用std::exit()或   例如std::abort()(18.5),不破坏类对象   具有自动存储持续时间 - 后注]

我认为这里强调的是“(但已完成)”部分。这包括一个例外(但不包括导致std::terminate的事物)。

修改

我认为更好的参考是§15.2/ 3构造函数和析构函数[except.ctor](强调我的):

  

如果初始化或销毁除了之外的对象   委托构造函数由异常终止,析构函数   为每个对象的直接子对象调用,对于a   完整对象,虚拟基类子对象,其初始化   已经完成(8.6)并且其析构函数尚未开始执行,   除了在破坏的情况下,a。的变体成员   类似联盟的阶级没有被摧毁。子对象被摧毁   完成他们的建设的相反顺序。这样   在进入处理程序之前对销毁进行排序   构造函数或析构函数的 function-try-block ,如果有的话。

这将包括聚合初始化(我今天学到的可以称为非空的初始化

...对于带有构造函数的对象,我们可以引用§12.6.2/ 12 [class.base.init](强调我的):

  

在非委托构造函数中,每个潜在的析构函数   可能会调用构造的类类型的子对象(12.4)。 [   注意:此规定可确保可以调用析构函数   完全构造的子对象,以防抛出异常(15.2)。    - 后注]

相关问题