我应该声明我的异常noexcept的拷贝构造函数吗?

qdi*_*dii 11 c++ exception copy-constructor noexcept c++11

更有效的C++中,Scott Meyers说

C++指定复制作为异常抛出的对象.

我想,如果复制构造函数依次抛出异常,std::terminate则会调用,所以这是声明所有异常的复制构造函数的一个很好的理由noexcept(而且,我想,不要抛出从堆中分配内存的对象,喜欢std::string).

然而,我惊讶地发现GCC 4.7.1附带的标准库实现没有为std::bad_alloc和定义那些复制构造函数std::exception.他们不应该定义它们noexcept吗?

How*_*ant 5

第 18.8.1 节 [例外]/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;
  };
}
Run Code Online (Sandbox Code Playgroud)

即 std::exception 的复制构造函数和复制赋值应为noexcept,并且可以通过以下方式进行测试:

static_assert(std::is_nothrow_copy_constructible<std::exception>::value, "");
static_assert(std::is_nothrow_copy_assignable<std::exception>::value, "");
Run Code Online (Sandbox Code Playgroud)

即如果一个实现没有使这些成员成为 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;
  };
}
Run Code Online (Sandbox Code Playgroud)

此外,所有std 定义的异常类型都显式或隐式地具有 noexcept 复制成员。对于在<stdexcept>此定义的类型,通常使用what()字符串的引用计数缓冲区来实现。这在 [exception]/p2 中有明确说明:

T从类异常派生的每个标准库类都应具有可公开访问的复制构造函数和不随异常退出的可公开访问的复制赋值运算符。...

也就是说,在一个质量实现中(并且在这方面创建一个质量实现并不需要英雄主义),异常类型的复制成员不仅不会抛出异常(自然是因为它们被标记noexcept),它们也不会调用terminate().

复制标准定义的异常类型没有失败模式。要么没有要复制的数据,要么数据是引用计数且不可变的。