【问题标题】:Should exceptions thrown from class member initializers call std::terminate()?类成员初始化程序抛出的异常是否应该调用 std::terminate()?
【发布时间】:2017-05-10 12:13:15
【问题描述】:

鉴于此代码:

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

哪种行为是正确的?

【问题讨论】:

  • Clang 是正确的。
  • 啊,是的!可能与 GCC PR 80683 中的问题相同。
  • 其他人最初将标题读为“这是一个好的设计模式”吗? ;)

标签: c++ c++11 exception exception-handling compiler-bug


【解决方案1】:

这是 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 B 的声明更改为显式 使用struct A 构造函数:

struct B {
    B():a(42) {}
    A a;
};

然后结果会如预期一样,我们将输入try/catch,即使删除“欢迎”打印输出:

ERROR: 42
0

【讨论】:

  • 搞笑(gcc (Gentoo 6.4.0-r1 p1.3) 6.4.0):$ g++ so-43892186.cpp -o so-43892186 &amp;&amp; ./so-43892186 --- Welcome --- terminate called after throwing an instance of 'int'
  • @BodoThiesen 我猜有些编译器允许跨 IO 指令重新排序,而有些则不允许。
【解决方案2】:

Clang 是正确的。可以在 C++ 标准参考草案 n4296(强调我的)中找到相关参考:

15.3 处理异常[except.handle]

...
3 处理程序匹配 E 类型的异常对象 if
(3.1) — 处理程序的类型为 cv T 或 cv T& 并且 E 和 T 是同一类型(忽略顶级 cv 限定符),

这里抛出了一个int,处理程序声明了一个const int。有一个匹配,应该调用处理程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多