【发布时间】:2012-10-14 01:12:34
【问题描述】:
C++11 规范明确隐式生成的特殊函数(即默认构造函数、析构函数、复制/移动构造函数和复制/移动赋值运算符)具有异常规范。但该规范似乎仅根据现已弃用的 dynamic 异常规范(即“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() 与违反了 noexcept ,程序的行为是不同的。
上面例子中15.4/14的文字是规范的,上面写着:
隐式声明的特殊成员函数(第 12 条) 应具有异常规范。如果 f 是隐式声明的 默认构造函数,复制构造函数,移动构造函数,析构函数, 复制赋值运算符,或移动赋值运算符,其隐式 exception-specification 指定类型 ID T 当且仅当 T 是 由直接调用的函数的异常规范所允许 由 f 的隐含定义; f 应允许所有例外情况(如果有) 它直接调用的函数允许所有异常,并且 f 应允许 如果它直接调用的每个函数都不允许 例外。
鉴于这里只提到了动态异常规范,我担心隐式生成的特殊成员函数永远不会被声明为noexcept。真的是这样吗?
【问题讨论】:
-
他们怎么可能被声明为
noexcept?您是否希望编译器检查您的代码并检查您是否从未抛出异常? -
@SethCarnegie:如果编译器推断出动态异常规范为
throw(),我希望编译器使用noexcept。 -
由于“12 [...] 具有不抛出异常规范的函数不允许任何异常。”,
noexcept或throw()中的任何一个都是有效的异常规范这不允许任何例外。这对于第 14 段来说似乎已经足够了,它特别不需要动态异常规范。我不确定我是否能很好地掌握整个情况以做出回答。 -
“这会有所不同,因为如果违反了 throw() 和违反了 noexcept,程序的行为是不同的。”真的吗?怎么样?
-
@Nemo 程序的行为在
throw()与noexcept的违规 的情况下有所不同,即如果实际抛出异常。noexcept调用std::terminate,在这种情况下可能没有完全展开堆栈。