给出这个代码:
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; } }
当编译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
但是当用Clang(版本4.0.0)编译时:
$clang++ -std=c++11 test.cpp -o test; ./test ; echo $? 42
哪个行为是正确的?
解决方法
这是GCC(
Bug 80683)中的一个错误.
如果构造函数是try / catch子句中的第一个操作,那么编译器认为它不在其中,尽管它应该包含它.
例如,以下工作很好:
#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; }
运行:
g++ -std=c++11 test.cpp -DNDEBUG -o test; ./test ; echo $?
输出:
Welcome ERROR: 42 0
我的猜测是,由于编译器优化,它将构造函数移动到主函数的开头.它假定struct B没有构造函数,那么它假定它不会抛出异常,因此可以将它移动到try / catch子句之外.
如果我们将struct struct的声明改为明确地使用struct A构造函数:
struct B { B():a(42) {} A a; };
那么结果将如预期的那样,我们将进入try / catch,即使删除“欢迎”打印输出:
ERROR: 42 0