Section 18.8.1 [exception]/p1 规定:
namespace std {
class exception {
public:
exception() noexcept;
exception(const exception&) noexcept;
exception& operator=(const exception&) noexcept;
virtual ~exception();
virtual const char* what() const noexcept;
};
}
即std::exception 的复制构造函数和复制赋值应为noexcept,可通过以下方式进行测试:
static_assert(std::is_nothrow_copy_constructible<std::exception>::value, "");
static_assert(std::is_nothrow_copy_assignable<std::exception>::value, "");
即如果一个实现没有使这些成员成为 noexcept,那么它在这方面是不符合的。
同样,18.6.2.1 [bad.alloc]/p1 也指定了 noexcept 复制:
namespace std {
class bad_alloc : public exception {
public:
bad_alloc() noexcept;
bad_alloc(const bad_alloc&) noexcept;
bad_alloc& operator=(const bad_alloc&) noexcept;
virtual const char* what() const noexcept;
};
}
此外,所有标准定义的异常类型都具有 noexcept 复制成员,无论是显式的还是隐式的。对于<stdexcept> 中定义的类型,通常使用what() 字符串的引用计数缓冲区来实现。这在 [exception]/p2 中有明确说明:
从类异常派生的每个标准库类T
应具有可公开访问的复制构造函数和可公开访问的
不以
例外。 ...
也就是说,在一个高质量的实现中(并且在这方面创建一个高质量的实现并不需要英雄主义),异常类型的副本成员不仅不会抛出异常(自然是因为它们被标记为noexcept) ,他们也不会打电话给terminate()。
复制标准定义的异常类型没有失败模式。要么没有要复制的数据,要么数据是引用计数且不可变的。