【问题标题】:Can copy elision occur in catch statements?复制省略可以发生在 catch 语句中吗?
【发布时间】:2011-09-13 21:43:04
【问题描述】:

考虑一个带有副作用的复制构造函数的异常类。

编译器能否在此处跳过调用复制构造函数:

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 的启发)

【问题讨论】:

    标签: c++ exception optimization copy-elision


    【解决方案1】:

    是的,在投掷和接球过程中都可以忽略它。只有当 catch 子句中指定的类型与异常对象的类型相同(除了 cv-qualifications)时,才能忽略它。更正式和更详细的描述见 C++11 12.8/31。

    ...这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):

    ...

    • 在 throw 表达式中,当操作数是非易失性自动对象(函数或 catch 子句参数除外)的名称时,其范围未超出最内层封闭 try 块的末尾(如果有一个),可以通过将自动对象直接构造到异常对象中来省略从操作数到异常对象(15.1)的复制/移动操作

    ...

    • 当异常处理程序的异常声明(第 15 条)声明与异常对象 (15.1) 具有相同类型的对象(cv 限定除外)时,可以通过处理异常来省略复制/移动操作-declaration 作为异常对象的别名,如果程序的含义将保持不变,除了为异常声明声明的对象执行构造函数和析构函数。

    【讨论】:

    • 很有趣,虽然引用的范围很窄......所以很难确定它实际上是指这种特殊情况。
    • @Mattieu:我有点懒得添加所有相关的引用,无论如何,就在这里。
    • 感谢您毫无疑问的报价 :)
    【解决方案2】:

    我认为这是特别允许的。对于 C++03,15.1/3 说:

    throw 表达式初始化一个临时对象,称为 异常对象,

    12/15 说:

    当一个临时类对象没有绑定到一个引用 (12.2) 将被复制到具有相同 cv-unqualified 的类对象 类型,可以通过构造 tempo- 来省略复制操作 rary 对象直接放入省略副本的目标中

    因此,保存运行中异常的秘密隐藏位置被标准定义为临时的,因此对复制省略有效。

    编辑:哎呀,我现在已经阅读了更多内容。 15.1/5:

    如果使用临时对象可以不用改变就可以消除 程序的意义除了构造函数的执行 和与使用临时对象相关的析构函数 (12.2),那么可以直接初始化handler中的异常 使用 throw 表达式的参数。

    不太清楚。

    它是否真的会......如果 catch 子句要重新引发异常(包括如果它调用了可能这样做的不可见代码),那么实现仍然需要“称为异常对象的临时对象”待在身边。因此,何时可以进行复制省略可能会有一些限制。显然,一个空的 catch 子句不能重新引发它。

    【讨论】:

      【解决方案3】:

      是的。如果catch 通过reference 捕获异常,则不会有复制(嗯,这是根据定义)。

      但我认为这不是你的问题,而且我相信你编写的代码是故意编写的,没有提及 reference。如果是这种情况,那么是的,即使在这种情况下,也可以省略复制。实际上,catch 中变量的初始化在理论上是直接初始化。并且编译器可以在可能的情况下省略直接初始化中的复制。

      C++03 §8.5/14 读取,

      [...] 在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除这种直接初始化中固有的复制;

      【讨论】:

      • 这里没有引用,只考虑按值捕获时的复制省略。
      • @Matthieu:我的大部分回答都解决了这个问题。我想你只看了第一句话?
      • 关于标准报价:目前尚不清楚它是否涉及一般的复制省略或仅涉及catch,您能否准确地说?
      • 我没有只读第一句话,其余的答案实际上很有趣......但为什么要从 OP 没有问的东西开始呢?
      • @Matthieu:可能是他想避免复制,但不知道如何,这就是我写第一句话的原因。 :D
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多