为什么`std:variant`的operator =(T && t)的noexcept规范不依赖于内部类型的析构函数的noexcept规范?

时间:2018-10-08 15:46:48

标签: c++ variant nothrow std-variant

长标题:为什么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)

这似乎不正确。我想念什么吗?

1 个答案:

答案 0 :(得分:6)

通常,标准库类型不适用于具有抛出析构函数的类型。或具体来说,当析构函数实际发出异常时。有一个一般规则(stopImmediatePropagation

  

在某些情况下(替换函数,处理函数,用于实例化标准库模板组件的类型的操作),C ++标准库取决于C ++程序提供的组件。如果这些组件不符合要求,则本国际标准对实施没有任何要求。

     

尤其是在以下情况下,效果是不确定的:

     

...

     
      
  • 如果任何替换函数或处理函数或析构函数操作通过异常退出,除非适用的“必需的行为:”段落中特别允许。
  •   

由于variant::operator=没有关于抛出析构函数的特殊声明,因此让那些析构函数实际抛出是UB。