c – 从类成员初始化器抛出的异常是否调用std :: terminate()?

给出这个代码
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

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...