g++-4.8.1认为没有异常说明的显式声明的析构函数总是noexcept(true)
g++-4.8.1 thinks that an explicitly-declared destructor with no exception specification is always noexcept(true)
考虑以下程序:
#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)
。
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)
?
Update:我打开了一个bug: 57645。如果您确实需要解决这个问题,您可以向析构函数添加异常规范(就像示例中的Thrower
一样)。
TL;DR:为什么g++-4.8.1认为没有异常说明的显式声明的析构函数总是
noexcept(true)
?
因为它有bug?
你对标准的解释是正确的,Clang正确地实现了它(assert没有触发)。
f
有异常规范noexcept(true)
,如果它直接调用的每个函数不允许异常。
析构函数直接调用所有子对象的析构函数:
§12.4 [class.dtor] p8
:
在执行析构函数体并销毁在析构函数体中分配的任何自动对象之后,类
X
的析构函数调用X的直接非变量非静态数据成员,[…]的析构函数。
相关文章:
- 如果在C++中不需要构造函数或析构函数,是否有必要显式声明它?
- 为什么 "=default" 析构函数与隐式声明的析构函数不同?
- 我们什么时候应该在 C++ 中将析构函数声明为 =DELETE
- 析构函数在 lambda 捕获说明符中声明的类实例上运行两次
- 为什么在声明析构函数时必须声明 copy & move 构造函数?
- 当声明了虚拟析构函数但没有实现时会发生什么情况
- 析构函数删除在 main 中声明的动态数组
- 显式声明派生类中所需的析构函数
- 缺少析构函数声明
- 结构sqlite3的sqlite3c++正向声明导致析构函数中删除时出现无效指针错误
- 为什么简单析构函数在使用基指针声明时不删除派生对象
- C++自动生成带有用户声明析构函数的移动构造函数
- 不稳定的声明行为:Rational.h:25:错误:在"&"标记之前预期的构造函数、析构函数或类型转换
- C++ - 如果在循环中声明对象,是否在循环结束时调用其析构函数
- 如何在不中断移动和复制构造函数的情况下声明虚拟析构函数
- 声明析构函数虚拟就足够了吗?
- 为什么允许我声明一个带有已删除析构函数的对象
- 在类中声明并在 Main 中创建对象时隐式调用析构函数
- Forward声明和析构函数之间的关系
- 如果类至少包含一个虚拟函数,是否总是需要将析构函数声明为虚拟函数