16

考虑以下程序:

#include <type_traits>

struct Thrower
{
    ~Thrower() noexcept(false) { throw 1; }
};

struct Implicit
{
    Thrower t;
};
static_assert(!std::is_nothrow_destructible<Implicit>::value, "Implicit");

struct Explicit
{
    ~Explicit() {}

    Thrower t;
};
static_assert(!std::is_nothrow_destructible<Explicit>::value, "Explicit");

有了g++-4.8.1,就出现了静态断言失败Explicit——好像是这样认为~Explicit()noexcept。这不符合我的期望。根据§12.4.3:

没有异常规范的析构函数声明被隐式认为具有与隐式声明相同的异常规范

这里有趣的是,检查的Implicit行为似乎符合我对 §15.4.14 的解释(通过 §12.4.7)。

...如果f是一个...析构函数...它的隐式异常规范指定...noexcept(true)如果它直接调用的每个函数都不允许异常,则 f 具有异常规范。

g++-4.7缺乏is_nothrow_destructable,我写了自己的来检查 4.7 中的行为。该程序似乎编译得很好。我保留完全错误的权利和我困惑的根源:

template <typename T>
struct is_nothrow_destructible
{
    static constexpr bool value = noexcept(std::declval<T>().~T());
};

TL;DR:为什么g++-4.8.1认为明确声明的没有异常规范的析构函数总是 noexcept(true)


更新:我打开了一个错误:57645。如果您确实需要解决此问题,可以向析构函数添加异常规范(如Thrower示例中的 has)。

4

1 回答 1

7

TL;DR:为什么 g++-4.8.1 认为明确声明的没有异常规范的析构函数总是noexcept(true)

因为它有一个错误?

您对标准的解释是正确的,并且 Clang 正确地实现了它(断言不会触发)。

fnoexcept(true)如果它直接调用的每个函数都不允许异常,则具有异常规范。

析构函数直接调用所有子对象的析构函数:

§12.4 [class.dtor] p8

在执行析构函数的主体并销毁主体内分配的任何自动对象后,X的析构函数调用 X 的直接非变体非静态数据成员的析构函数,[...]。

于 2013-06-18T20:34:20.870 回答