是否复制构造函数和std :: runtime_error的复制赋值noexcept?

Nor*_*rci 10 c++ exception-handling c++14

所有GCC 4.8.4,4.9.3,5.3.0都通过了测试std::exception(对于任何-std = c ++ 11/1y/14/1z/17选项,如果可用):

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

这很好,因为std::exception没有特殊成员(C++ 14 18.8.1):

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)

不幸的是,上面的所有编译器都失败了以下static_asserts:

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

该标准仅包含std::runtime_error19.2.6中的以下内容:

namespace std {
  class runtime_error : public exception {
  public:
    explicit runtime_error(const string& what_arg);
    explicit runtime_error(const char* what_arg);
  };
}
Run Code Online (Sandbox Code Playgroud)

但是没有任何关于noexcept其他(隐含声明的特殊)成员的内容以及存储实现要求的说法what_arg.

标准(C++ 14)在15.4/14中说明如下:

继承构造函数(12.9)和隐式声明的特殊成员函数(子句12)具有异常规范.如果f是继承构造函数或隐式声明的默认构造函数,复制构造函数,移动构造函数,析构函数,复制赋值运算符或移动赋值运算符,则其隐式异常规范指定type-id T当且仅当T允许时才由f的隐式定义直接调用的函数的异常规范; f允许所有异常,如果它直接调用的任何函数允许所有异常,并且f具有异常规范noexcept(true),如果它直接调用的每个函数都不允许异常.

以及18.8.1/2中的以下内容:

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

由于std::runtime_error不公开what_arg存储的实现,我们不知道它的(特殊)成员是否是noexcept,因此std::runtime_error复制构造函数或复制赋值成员的noexceptness 是不可判定的.我们唯一的赌注是18.8.1以上.

问题1/a)我们考虑std::runtime_error的拷贝构造函数或拷贝赋值被noexcept(1,2).这是真的/最先进的/最佳实践吗?

问题1/b)我们不需要在标准中明确说明这一点吗?(如18.8.2,班级bad_exception)

问题1/c)GCC中的错误是上面的static_assert测试失败了吗?

问题2)如果上面的推论是错误的,有人可以指向标准中的段,其中说明std :: runtime_error没有复制构造函数(和复制赋值)吗?(或者说它们不是.)

Col*_*mbo 2

考虑LWG 1371

第 19 条中定义的异常类型都不允许在复制或移动操作上抛出异常,但没有明确规范这些操作有异常规范来证明这一点。请注意,隐式声明的构造函数从其基类(最终)获取异常规范,如果其所有数据成员都类似地声明操作,std::exception则将隐式生成异常规范。由于表示未指定,我们不能假设非抛出操作,除非我们明确地将其声明为对实现的约束。noexceptnoexcept

[投票评论提出的决议:]

添加全局保证,即第 19 条中定义的依赖于隐式声明的操作的所有异常类型在这些操作上都具有不引发异常规范。

在2010年的巴达维亚会议上,发现[exception]/2 “涵盖了这一点”:

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

因此,仍然没有强制要求这些特殊成员函数是noexcept. 根据[except.spec]/16中确定隐式异常规范的方式,由于实现可以添加带有默认参数和成员的任意参数,因此无论这些特殊成员函数是否是,它都是特定于实现的noexcept