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

Mate059

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

我可以在cppreference 上看到

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)

std::variant<FooThrow, int> x;
x = 3; // throws

好像不对。我错过了什么吗?

尼可波拉斯

通常,标准库类型对具有抛出析构函数的类型不友好。或者具体来说,当析构函数实际发出异常时。关于它有一个一般规则([res.on.functions]

在某些情况下(替换函数、处理函数、用于实例化标准库模板组件的类型操作),C++ 标准库依赖于由 C++ 程序提供的组件。如果这些组件不满足它们的要求,本国际标准不对其实施提出要求。

特别是,在以下情况下效果是不确定的:

...

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章