jot*_*tik 12 c++ exception-handling exception compiler-bug c++11
鉴于此代码:
struct A {
A(int e) { throw e; }
};
struct B {
A a{42}; // Same with = 42; syntax
};
int main() {
try {
B b;
} catch (int const e) {
return e;
}
}
Run Code Online (Sandbox Code Playgroud)
使用GCC编译时(版本4.7.4,4.8.5,4.9.3,5.4.0,6.3.0):
$ g++ -std=c++11 test.cpp -o test; ./test ; echo $?
terminate called after throwing an instance of 'int'
Aborted
134
Run Code Online (Sandbox Code Playgroud)
但是在使用Clang(版本4.0.0)编译时:
$ clang++ -std=c++11 test.cpp -o test; ./test ; echo $?
42
Run Code Online (Sandbox Code Playgroud)
哪种行为是正确的?
Lir*_*aro 10
这是GCC中的一个错误(Bug 80683).
如果构造函数是try/catch子句中的第一个op ,那么编译器认为它在它之外,尽管它应该包含它.
例如,以下工作正常:
#include <iostream>
struct A {
A(int e) { throw e; }
};
struct B {
A a{42}; // Same with = 42; syntax
};
int main() {
try {
// The following forces the compiler to put B's contructor inside the try/catch.
std::cout << "Welcome" << std::endl;
B b;
} catch (int e) {
std::cout << "ERROR: " << e << std::endl; // This is just for debugging
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
运行:
g++ -std=c++11 test.cpp -DNDEBUG -o test; ./test ; echo $?
Run Code Online (Sandbox Code Playgroud)
输出:
Welcome
ERROR: 42
0
Run Code Online (Sandbox Code Playgroud)
我的猜测是,由于编译器优化,它将构造函数移动到main函数的开头.它假定它struct B没有构造函数,然后它假定它永远不会抛出异常,因此将它移到try/catch子句之外是安全的.
如果我们将更改声明struct B以显式使用struct A构造函数:
struct B {
B():a(42) {}
A a;
};
Run Code Online (Sandbox Code Playgroud)
然后结果将如预期的那样,我们将进入try/catch,即使删除"欢迎"打印输出:
ERROR: 42
0
Run Code Online (Sandbox Code Playgroud)