C++ 标准是否保证统一初始化是异常安全的?
Does the C++ standard guarantee that uniform initialization is exception-safe?
#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 的一个严重错误。
参考 GCC bug 66139 and "A serious bug in GCC" by Andrzej Krzemieński。
我只是想知道:
C++ 标准是否保证统一初始化是异常安全的?
好像是:
在所有地方(N4618)的§6.6/2跳转语句[stmt.jump]中奇怪地发现:
On exit from a scope (however accomplished), objects with automatic
storage duration (3.7.3) that have been constructed in that scope are
destroyed in the reverse order of their construction. [ Note: For
temporaries, see 12.2. —end note ] Transfer out of a loop, out of a
block, or back past an initialized variable with automatic storage
duration involves the destruction of objects with automatic storage
duration that are in scope at the point transferred from but not at
the point transferred to. (See 6.7 for transfers into blocks). [ Note:
However, the program can be terminated (by calling std::exit()
or
std::abort()
(18.5), for example) without destroying class objects
with automatic storage duration. —end note ]
我认为这里的重点是“(无论如何完成)”部分。这包括一个例外(但不包括导致 std::terminate
的事情)。
编辑
我认为更好的参考是§15.2/3构造函数和析构函数[except.ctor](强调我的):
If the initialization or destruction of an object other than by
delegating constructor is terminated by an exception, the destructor
is invoked for each of the object’s direct subobjects and, for a
complete object, virtual base class subobjects, whose initialization
has completed (8.6) and whose destructor has not yet begun execution,
except that in the case of destruction, the variant members of a
union-like class are not destroyed. The subobjects are destroyed in
the reverse order of the completion of their construction. Such
destruction is sequenced before entering a handler of the
function-try-block of the constructor or destructor, if any.
这会包括聚合初始化(我今天了解到可以称为非空初始化)
...对于具有构造函数的对象,我们可以引用§12.6.2/12 [class.base.init](强调 我的):
In a non-delegating constructor, the destructor for each potentially
constructed subobject of class type is potentially invoked (12.4). [
Note: This provision ensures that destructors can be called for
fully-constructed subobjects in case an exception is thrown (15.2).
—end note ]
#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 的一个严重错误。
参考 GCC bug 66139 and "A serious bug in GCC" by Andrzej Krzemieński。
我只是想知道:
C++ 标准是否保证统一初始化是异常安全的?
好像是:
在所有地方(N4618)的§6.6/2跳转语句[stmt.jump]中奇怪地发现:
On exit from a scope (however accomplished), objects with automatic storage duration (3.7.3) that have been constructed in that scope are destroyed in the reverse order of their construction. [ Note: For temporaries, see 12.2. —end note ] Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of objects with automatic storage duration that are in scope at the point transferred from but not at the point transferred to. (See 6.7 for transfers into blocks). [ Note: However, the program can be terminated (by calling
std::exit()
orstd::abort()
(18.5), for example) without destroying class objects with automatic storage duration. —end note ]
我认为这里的重点是“(无论如何完成)”部分。这包括一个例外(但不包括导致 std::terminate
的事情)。
编辑
我认为更好的参考是§15.2/3构造函数和析构函数[except.ctor](强调我的):
If the initialization or destruction of an object other than by delegating constructor is terminated by an exception, the destructor is invoked for each of the object’s direct subobjects and, for a complete object, virtual base class subobjects, whose initialization has completed (8.6) and whose destructor has not yet begun execution, except that in the case of destruction, the variant members of a union-like class are not destroyed. The subobjects are destroyed in the reverse order of the completion of their construction. Such destruction is sequenced before entering a handler of the function-try-block of the constructor or destructor, if any.
这会包括聚合初始化(我今天了解到可以称为非空初始化)
...对于具有构造函数的对象,我们可以引用§12.6.2/12 [class.base.init](强调 我的):
In a non-delegating constructor, the destructor for each potentially constructed subobject of class type is potentially invoked (12.4). [ Note: This provision ensures that destructors can be called for fully-constructed subobjects in case an exception is thrown (15.2). —end note ]