所有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(1,2) . 这是真的/最先进的/最佳实践吗?
问题1 / b)我们不需要在标准中明确说明这一点吗? (如18.8.2,类 bad_exception
)
问题1 / c)GCC中的错误是上面的static_assert测试失败了吗?
问题2)如果上面的推论是错误的,有人可以指向标准中的段,其中说明std :: runtime_error没有复制构造函数(和复制赋值)吗? (或者说它们不是 . )
1 回答
考虑LWG 1371:
在2010年巴达维亚 Session 上,发现[exception]/2 "covered this":
因此,仍然没有规定这些特殊成员职能是
noexcept
. 并且根据[except.spec]/16中确定隐式异常规范的方式,由于实现可以使用默认参数和成员添加任意参数,因此无论这些特殊成员函数是否为noexcept
,它都是特定于实现的 .