长标题:为什么std:variant
的{{1}}的noexcept规范不依赖于内部类型的析构函数的noexcept规范?
我可以在cppreference上看到
operator=(T&& t)
是
template <class T> variant& operator=(T&& t) noexcept(/* see below */);
因此,它将编译:
noexcept(std::is_nothrow_assignable_v<T_j&, T> &&
std::is_nothrow_constructible_v<T_j, T>)
但是它调用struct FooThrow {
~FooThrow() noexcept(false) {throw;}
};
static_assert(std::is_nothrow_assignable_v<std::variant<FooThrow, int>, int>);
的析构函数,即FooThrow
:
noexcept(false)
这似乎不正确。我想念什么吗?
答案 0 :(得分:6)
通常,标准库类型不适用于具有抛出析构函数的类型。或具体来说,当析构函数实际发出异常时。有一个一般规则(stopImmediatePropagation
)
在某些情况下(替换函数,处理函数,用于实例化标准库模板组件的类型的操作),C ++标准库取决于C ++程序提供的组件。如果这些组件不符合要求,则本国际标准对实施没有任何要求。
尤其是在以下情况下,效果是不确定的:
...
- 如果任何替换函数或处理函数或析构函数操作通过异常退出,除非适用的“必需的行为:”段落中特别允许。
由于variant::operator=
没有关于抛出析构函数的特殊声明,因此让那些析构函数实际抛出是UB。