3

长标题:为什么std:variant'soperator=(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

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

4

1 回答 1

6

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

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

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

...

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

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

于 2018-10-08T15:53:13.993 回答