You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确检查C++析构函数是否为noexcept?

析构函数noexcept检查不符合预期的原因分析

核心规则:C++析构函数的默认noexcept属性

C++标准明确规定:析构函数默认是noexcept(true),仅在以下两种情况会变为noexcept(false):

  • 显式声明为~T() noexcept(false);
  • 类的基类或非静态成员的析构函数是noexcept(false),此时当前类析构函数的noexcept会被自动推导为false。

注意:析构函数的noexcept属性由声明决定,和函数体内部是否实际抛出异常无关。这是析构函数和普通成员函数的关键区别——普通成员函数默认是noexcept(false)。


逐个解释示例中的断言问题

1. static_assert(is_noexcept_destructible<Baddy>); 结果为true

自定义的is_noexcept_destructible通过noexcept(std::declval<T&&>().~T())判断,而Baddy的析构函数未显式声明noexcept,默认是noexcept(true),因此结果符合标准。

2. static_assert(std::is_nothrow_destructible_v<Baddy>); 结果为true

std::is_nothrow_destructible_v的作用是判断类型的析构函数是否能被noexcept调用。由于Baddy的析构函数默认noexcept(true),因此返回true。该特性仅关注析构函数的声明属性,不关心函数体是否实际抛出异常。

3. static_assert(not noexcept(Baddy().~Baddy())); 结果为false

Baddy()创建临时对象后调用析构函数,因析构函数默认noexcept(true),noexcept(Baddy().~Baddy())的结果为true,取反后为false,断言失败。这是标准规定的行为,和函数体内部抛出异常无关。

4. static_assert(not noexcept(Baddy().fn())); 结果为false(你认为的“universally false”)

普通成员函数默认是noexcept(false),因此noexcept(Baddy().fn())的结果应为false,取反后为true,断言本应通过。你看到的失败可能是编译器特殊行为或代码书写误差,但从标准规则来看,这个断言的预期逻辑有误。

5. static_assert(not noexcept(Gooddy().~Gooddy())); 结果为false

Gooddy的析构函数显式声明为noexcept(true),因此noexcept(Gooddy().~Gooddy())的结果为true,取反后为false,断言失败是符合预期的——析构函数确实是noexcept(true)。

6. static_assert(not noexcept(Gooddy().fn())); 结果为false

Gooddy::fn()显式声明为noexcept(true),因此noexcept(Gooddy().fn())的结果为true,取反后为false,断言失败是正确的,和函数的实际noexcept属性一致。


关于std::declval的疑问

std::declval对析构函数的判断是有效的,之所以看起来“失效”,是因为你误解了析构函数的默认noexcept规则——它默认是true,而非普通成员函数的默认false。

内容的提问来源于stack exchange,提问作者mariusm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 07:32:12