隐式生成的成员和 noexcept
Posted
技术标签:
【中文标题】隐式生成的成员和 noexcept【英文标题】:Implicit generated members and noexcept 【发布时间】:2012-02-07 16:41:15 【问题描述】:我最近开始添加新的noexcept
规范以尽可能移动构造函数/赋值。现在我开始想知道隐式生成的成员函数的异常规范是什么样的。由于拥有noexcept
移动函数允许使用更有效的代码路径(例如,在调整vector
的大小时)我希望尽可能将它们声明为noexcept。我无法理解标准对此的规定,因此尝试了 g++4.6 中的以下代码(使用-std=c++0x
)来掌握它:
struct foobar;
int main()
foobar a, b;
std::cout<<std::boolalpha
<<noexcept(foobar())<<", "<<noexcept(foobar(a))<<", "
<<noexcept(a = b) <<", "<<noexcept(a = std::move(b))<<", "
<<noexcept(foobar(std::move(a)))<<std::endl;
这给了我True, True, True, False, False
的输出,这意味着noexcept
的默认和复制构造函数/赋值,而不是移动操作。
现在回答我的问题:
在什么情况下隐式生成(或默认)的成员函数声明为noexcept
?此外,foobar
观察到的行为是正确的还是只是 gcc4.6 中的编译器错误?
【问题讨论】:
【参考方案1】:库错误 — 它在 gcc 4.7 中显示 true, true, true, true, true
。
错误是不是生成的移动构造函数不是 noexcept,而是 std::move
没有标记为 noexcept
,正如我们在附加测试中看到的那样:
std::cout << noexcept(a = static_cast<foobar&&>(b)) << ", " // true
<< noexcept(foobar(static_cast<foobar&&>(b))) << ", " // true
<< noexcept(std::move(b)) << std::endl; // false
gcc 4.6 中的大多数库函数都不是 noexcept 正确的,这已在 gcc 4.7 中得到解决,
至于隐含生成的成员函数何时为 noexcept,这在 §15.4/14 中有记录。基本上,如果它需要调用的所有函数都是noexcept
,它就是noexcept
。
隐式声明的特殊成员函数(第 12 条)应具有异常规范。如果
f
是 隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值 运算符或移动赋值运算符,其隐含的 exception-specification 指定 type-idT
当且仅 如果T
被f
的隐式定义直接调用的函数的异常规范 允许;f
应 如果它直接调用的任何函数允许所有异常,则允许所有异常,和f
不应允许任何异常 如果它直接调用的每个函数都不允许出现异常。
【讨论】:
那么这是否意味着这些函数尽可能是noexcept
(也就是它们不调用任何抛出函数)?
@Grizzly:我认为这意味着如果他们只调用noexcept
函数,他们将是noexcept
(即是否调用throw 的实际函数无关紧要,异常规范才是重要的) 以上是关于隐式生成的成员和 noexcept的主要内容,如果未能解决你的问题,请参考以下文章
区别 b/w 在 C# 中隐式实现成员和显式实现成员 [重复]