考虑一个带有副作用的复制构造函数的异常类。
编译器是否可以跳过调用复制构造函数:
try {
throw ugly_exception();
}
catch(ugly_exception) // ignoring the exception, so I'm not naming it
{ }
这个怎么样:
try {
something_that_throws_ugly_exception();
}
catch(ugly_exception) // ignoring the exception, so I'm not naming it
{ }
(是的,我知道这一切都非常难看,这是受another question)启发的
答案 0 :(得分:9)
是的,在投掷和捕捉期间都可以省略。对于捕获,只有当catch子句中指定的类型与异常对象的类型相同(保存为cv-qualifications)时,才能省略它。有关更正式和详细的说明,请参阅C ++ 11 12.8 / 31.
......在下列情况下(允许合并以消除多份副本),允许复制/移动操作(称为复制省略)的省略:
...
- 在throw-expression中,当操作数是非易失性自动对象的名称(函数或catch子句参数除外),其范围不会超出最内层封闭try-block的末尾(如果有一个),通过直接将自动对象构造成异常对象,可以省略从操作数到异常对象(15.1)的复制/移动操作
...
- 当异常处理程序的异常声明(第15条)声明一个相同类型的对象(cv-qualification除外)作为异常对象(15.1)时,可以通过处理异常来省略复制/移动操作-declaration作为异常对象的别名,如果程序的含义将保持不变,除了执行异常声明声明的对象的构造函数和析构函数。
答案 1 :(得分:4)
我认为这是特别允许的。对于C ++ 03,15.1 / 3说:
throw-expression初始化一个名为的临时对象 异常对象,
和12/15说:
当一个临时类对象尚未绑定到引用时 (12.2)将被复制到具有相同cv-nonqualified的类对象 类型,通过构造节奏可以省略复制操作 rary对象直接进入省略副本的目标
因此,保留飞行中异常的秘密藏身之处由标准定义为临时,因此对于复制省略有效。
编辑:哎呀,我现在已经进一步阅读了。 15.1 / 5:
如果可以在不改变的情况下消除临时对象的使用 除了执行构造函数之外,程序的含义 和使用临时对象相关的析构函数 (12.2),然后可以直接初始化处理程序中的异常 使用throw表达式的参数。
没有更清楚。
它是否真的会...如果catch子句要重新引发异常(包括它是否会调用可见的非可见代码),那么实现需要“临时对象称为异常对象”仍然要在身边。因此,可能存在一些限制,以便何时可以进行复制。显然,空的catch子句不能重新提升它。
答案 2 :(得分:0)
是。如果catch
通过引用捕获到异常,那么就不会有副本(好吧,根据定义)。
但我认为这不是你的问题,我相信你写的代码是故意编写的,没有提及 reference 。如果是这种情况,那么是的,即使在这种情况下,也可以省略复制。实际上,catch
中的变量的初始化理论上是直接初始化。在可能的情况下,编译器可以省略直接初始化中的复制。
C ++03§8.5/ 14读取,
[...]在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除此直接初始化中固有的复制;