c – noexcept(false)析构函数会覆盖所有特殊成员函数的异常规范吗?

考虑这个T类

struct T{ 
    T() noexcept (true) {}
    T(T&& ) noexcept (true) {}          
    T(const T& ) noexcept (true) {}

    T& operator = (T&&) noexcept(true) { return *this; }
    T& operator = (const T&) noexcept(true) { return *this; }

    ~T() noexcept(false) {}
};

考虑这个简单的测试程序:

int main(){
    constexpr bool default_ctor = noexcept(T());
    static_assert(default_ctor == true, "Default Constructor can throw exceptions");

    constexpr bool move_ctor = noexcept(T(std::declval<T>())); //Move ctor
    static_assert(move_ctor == true, "Move Constructor can throw exceptions");

    constexpr bool copy_ctor = noexcept(T(std::declval<T&>())); //Copy ctor
    static_assert(copy_ctor == true, "Copy Constructor can throw exceptions");

    constexpr bool move_assign = noexcept(std::declval<T>() = std::declval<T>());
    static_assert(move_ctor == true, "Move Assignment can throw exceptions");

    constexpr bool copy_assign = noexcept(std::declval<T&>() = std::declval<const T&>());
    static_assert(copy_ctor == true, "Copy Assignment can throw exceptions");


    //It doesn't matter when using *`type_traits`* either. Same behavior:
    constexpr bool no_throw_cons = std::is_nothrow_constructible<T>::value;
    static_assert(no_throw_cons == true, "Default Constructor isn't nothrow");
    //...others skipped for brevity
}

这里每一个static_assert都会触发.这不应该是我从标准中理解的:

> g++ (GCC) 6.1.0
> clang (LLVM) 3.8.0
> MSVC (Visual Studio 2015)

但是,当你在没有异常规范的情况下声明T的析构函数(在这个简单的上下文中与noexcept(true)相同)时,所有的断言都会传递!

> g++ (GCC) 6.1.0
> clang (LLVM) 3.8.0
> MSVC (Visual Studio 2015)

但是,运行时遵循规范:

struct T{ 
    T() noexcept (true) { throw int(8); }
    //.... there rest omitted for brevity
    ~T() noexcept(false) {}
};

int main(){
    T a;
    (void)a;
};

按预期调用std :: terminate.

> g++ (GCC) 6.1.0
> clang (LLVM) 3.8.0
> MSVC (Visual Studio 2015)

C标准的任何部分是否定义或暗示了这种行为?析构函数上的noexcept(false)说明符仅在编译时覆盖每个特殊成员函数的异常规范?

或者这是每个主要编译器中的前端错误.

最佳答案 在您的第一个测试中,您询问完整表达式T()是否可以抛出异常.该表达式构造一个T然后再次销毁它.因此,如果析构函数可以抛出,那么表达式也可以抛出.

点赞