首页 文章

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

提问于
浏览
10

所有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");

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

namespace std {
类异常{
上市:
exception()noexcept;
异常(const异常&)noexcept;
exception&operator =(const exception&)noexcept;
virtual~exception();
virtual const char * what()const noexcept;
};
}

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

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");

该标准仅包含以下关于19.2.6中的 std::runtime_error

namespace std {
class runtime_error:public exception {
上市:
显式runtime_error(const string&what_arg);
显式runtime_error(const char * what_arg);
};
}

但是没有任何关于其他(隐式声明的特殊)成员的 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(12) . 这是真的/最先进的/最佳实践吗?

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

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

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

1 回答

  • 2

    考虑LWG 1371

    第19节中定义的任何异常类型都不允许在复制或移动操作上引发异常,但没有明确规定操作具有异常规范来证明它 . 请注意,隐式声明的构造函数从其基类(最终是std :: exception)获取异常规范将隐式生成noexcept异常规范,如果它们的所有数据成员类似地声明noexcept操作 . 由于表示未指定,我们不能假设非抛出操作,除非我们明确地将其声明为实现的约束 . [通过选票评论提出的决议:]添加一个全局保证,即第19节中定义的所有依赖于隐式声明的操作的异常类型都对这些操作具有非抛出异常规范 .

    在2010年巴达维亚 Session 上,发现[exception]/2 "covered this":

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

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


相关问题