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

#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的一个严重的错误。

有关参考,请参阅AndrzejKrzemieński的GCC错误66139和“GCC中的严重错误” 。

我只是好奇:

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

看起来如此:

在所有地方的§6.6/ 2 Jump Statements [stmt.jump](N4618)中奇怪的发现:

在从作用域(不pipe是否已完成)退出时,在该作用域中构build的具有自动存储持续时间(3.7.3)的对象将按其构造的相反顺序销毁。 [注:临时参见12.2。 – 结束注释]从循环中移出,从块中移出,或者通过具有自动存储持续时间的初始化variables返回,包括自动存储持续时间在对象范围内的对象的销毁, 。 (见6.7转入区块)。 [注意:但是,程序可以被终止(例如,通过调用std::exit()std::abort() (18.5)),而不会破坏具有自动存储持续时间的类对象。 – 注意]

我认为这里强调的是“(无论如何完成)”部分。 这包括一个exception(但不包括导致std::terminate东西)。


编辑

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

如果通过委托构造函数以外的对象的初始化或销毁被exception终止, 则为每个对象的直接子对象调用析构函数 ,对于完整对象, 调用析构函数 ,初始化已完成(8.6)的虚拟基类子对象其破坏者尚未开始执行,除非破坏情况下,类工会类别的变体成员不被销毁。 子对象按照完成build造的相反顺序被销毁。 在进入构造函数或析构函数的function-try-block的处理程序(如果有的话)之前,这种破坏是sorting的。

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

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

在非委托构造函数中,可能调用每个可能构造的类types子对象的析构函数(12.4)。 [注意: 这个规定确保在抛出exception的情况下可以为完全构造的子对象调用析构函数 (15.2)。 – 注意]