为什么 std:variant 的 operator=(T&& t) 的 noexcept 规范不依赖于内部类型的析构函数的 noexcept 规范?
Why `std:variant`'s `operator=(T&& t)`'s noexcept spec doesn't depend on inner types's destructor's noexcept spec?
长标题:为什么 std:variant
的 operator=(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] )
In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C ++ standard library depends on components supplied by a C ++ program. If these components do not meet their requirements, this International Standard places no requirements on the implementation.
In particular, the effects are undefined in the following cases:
...
- if any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable Required behavior: paragraph.
因为variant::operator=
没有关于抛出析构函数的特殊声明,所以让那些析构函数实际抛出是UB。
长标题:为什么 std:variant
的 operator=(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] )
In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C ++ standard library depends on components supplied by a C ++ program. If these components do not meet their requirements, this International Standard places no requirements on the implementation.
In particular, the effects are undefined in the following cases:
...
- if any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable Required behavior: paragraph.
因为variant::operator=
没有关于抛出析构函数的特殊声明,所以让那些析构函数实际抛出是UB。