4

C++11 规范明确隐式生成的特殊函数(即默认构造函数、析构函数、复制/移动构造函数和复制/移动赋值运算符)具有异常规范。但该规范似乎仅根据现已弃用的动态异常规范(即“throw (T1, T2, T3)”)编写。这由 15.4/14 中的示例支持:

struct A {
  A();
  A(const A&) throw();
  A(A&&) throw();
  ~A() throw(X);
};
struct B {
  B() throw();
  B(const B&) throw();
  B(B&&) throw(Y);
  ~B() throw(Y);
};
struct D : public A, public B {
  // Implicit declaration of D::D();
  // Implicit declaration of D::D(const D&) throw();
  // Implicit declaration of D::D(D&&) throw(Y);
  // Implicit declaration of D::D() throw(X, Y);
};

我知道,注释不是规范的,但值得注意的是 D 的复制构造函数被声明throw()而不是noexcept. throw()它会有所不同,因为如果违反 a 与违反a ,程序的行为是不同的noexcept

示例上方 15.4/14 中的文本是规范性的,它说:

隐式声明的特殊成员函数(第 12 条)应具有异常规范。如果 f 是隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符或移动赋值运算符,则其隐式异常规范指定类型 ID T 当且仅当 T 的异常规范允许f 的隐式定义直接调用的函数;如果 f 直接调用的任何函数允许所有异常,则 f 应允许所有异常;如果 f 直接调用的每个函数都不允许异常,则 f 应不允许异常。

鉴于这里只提到了动态异常规范,我担心隐式生成的特殊成员函数永远不会被声明noexcept。真的是这样吗?

4

1 回答 1

1

我不相信是这样的。实际的要求只是“...f 如果它直接调用的每个函数都不允许异常,则不应允许异常”。

如上所述(§15.4/12):

throw()如果异常规范的形式为 ,noexceptnoexcept(常量表达式),其中常量表达式产生,则异常规范是非抛出的true。具有非抛出异常规范的函数不允许任何异常。

非抛出异常规范不允许任何异常并不完全是一个启示,但我认为它说明了非抛出异常规范描述中的措辞几乎逐字地反映在对隐式声明的特殊成员函数的要求中. 因此,在我看来,任何形式的非抛出异常规范(throw()ornoexceptnoexcept(<anything that converts to true>))都是允许的——而且这是专门设计的,而不仅仅是措辞上的意外。

于 2012-10-24T06:38:54.817 回答