【问题标题】:noexcept(false) Destructor overrides all special member functions' exception specification?noexcept(false) 析构函数覆盖所有特殊成员函数的异常规范?
【发布时间】:2017-01-09 19:29:44
【问题描述】:

考虑这个类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 都会触发。这不应该符合我对标准的理解:

但是,当您声明 T 的析构函数时没有异常说明(与此简单上下文中的 noexcept(true) 相同),所有断言都会通过!


但是,运行时遵守规范:

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

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

std::terminate 按预期调用。


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

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

【问题讨论】:

    标签: c++ gcc visual-c++ clang language-lawyer


    【解决方案1】:

    在您的第一个测试中,您询问完整表达式 T() 是否可以引发异常。该表达式构造了一个T然后再次销毁它。所以如果析构函数可以抛出,那么表达式也可以。

    【讨论】:

    • 哦……哎呀!我完全忘记了full-expression。谢谢。我也刚看到this note on cppreference。但是,注释暗示如果T 的析构函数为noexcept(true),则类型特征std::no_throw_constructible&lt;T&gt;::value 及其朋友是否将为true;对编译器供应商来说是一个开放式的决定,对吗?这意味着对于这种情况,我们不能完全依赖这种行为。?
    • 好的。谢谢。 (抱歉评论混淆)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 2011-09-26
    • 2014-08-25
    • 2013-06-15
    • 2021-09-14
    • 2023-03-05
    相关资源
    最近更新 更多