【问题标题】:C++11 copy elison and exception (catch argument)C++11 复制 elison 和异常(catch 参数)
【发布时间】:2017-03-07 16:07:53
【问题描述】:

在对代码进行审查后,我们在 try/catch 块中遇到了复制 elison 的问题。 阅读此页面后: cpp reference guide 尤其是这一段:

处理异常时,如果catch子句的参数与抛出的异常对象属于同一类型(忽略顶级cv-qualification),则省略副本,catch子句的主体访问异常对象直接,好像被引用抓住了

我认为 catch 中参数的复制省略会自动执行,但其中一位审阅者运行了一个简单的测试,表明编译器没有执行复制省略:

#include <iostream>

class A
{
public:
   A(){}
   A(const A&){
    std::cout<<"COPY CONSTRUCTOR\n";
   }
};

int main()
{
    try {
       throw A{};
    } catch(A a) {
       throw a;
    }
    return 0;
 }

编译时:

g++ a.cpp -std=c++11 -O3

我得到以下输出

COPY CONSTRUCTOR
COPY CONSTRUCTOR
terminate called after throwing an instance of 'A'
Aborted (core dumped)

我期待一个类似于(抛出异常时只调用一次复制构造函数)的输出:

COPY CONSTRUCTOR
terminate called after throwing an instance of 'A'
Aborted (core dumped)

测试已经在Linux Ubuntu 16.04 g++版本下运行:

 g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

是测试用例无效还是我对复制省略的理解有误? 非常感谢您的帮助

【问题讨论】:

  • 引用确实声明:在以下情况下,编译器可以省略类对象的复制和移动(C++11 起)构造函数,即使复制/移动(由于 C++11) 构造函数和析构函数具有可观察到的副作用。。仅仅因为它被允许并不意味着它会发生。
  • 我不太关心副本(无论如何这是一种特殊情况),但 catch(A a) 只是 看起来 错误,因为通过 const 引用进行捕获已经如此牢固地确立在 C++ 的世界里。更不用说对象切片的危险了。
  • 权威引用的 std 子句是 eel.is/c++draft/class.copy#elision-1.3

标签: c++ c++11 exception copy-constructor copy-elision


【解决方案1】:

处理异常时,如果catch子句的参数与抛出的异常对象属于同一类型(忽略顶级cv-qualification),则省略复制...

关于 cppreference 的措辞过于强烈。这是允许复制省略的情况列表。那应该是:“副本可以被省略”。

编译器似乎没有执行复制省略,即使它被允许这样做。


标准(草案)中的相关引述:

[class.copy.elision] / 1

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

[class.copy.elision] / 1.3

当异常处理程序的异常声明(子句 [except])声明与异常对象具有相同类型(cv-qualification 除外)的对象时,可以通过将异常声明视为省略复制操作异常对象的别名,如果程序的含义将保持不变,除了为异常声明声明的对象执行构造函数和析构函数。 [ 注意:异常对象不能移动,因为它始终是左值。 — 尾注 ]

【讨论】:

  • 你的意思是副作用,打印消息“COPY CONSTRUCTOR”?
  • 但是如何测试复制省略,我们必须依赖规范?
  • 它说“除了”。跳过有副作用的复制构造函数是复制省略的重点。
  • @Cubbi 因此,即使复制 ctor 或 dtor 具有可观察到的副作用,复制省略也是复制的遗漏。如果类型匹配,则在 catch 子句的参数中允许复制省略,但前提是没有可观察到的副作用,除了来自复制 ctor 或 dtor 的副作用。这不是多余的吗?除了复制省略已明确允许的副作用之外,还有哪些副作用变化?我(错误?)将此解释为复制省略通常允许的例外。真的只是重申允许对复制 ctor 和 dtor 的可观察效果进行更改吗?
  • @Cubbi 好的,我更改了答案以匹配它。但是,GCC 的行为似乎与我解释的方式非常相似:由于复制 ctor 的副作用,它不会忽略复制(即使看似允许)。如果没有它,如果通过引用或值(省略)捕获,则会生成相同的程序集。不过,这种行为也不违反对标准的这种解释。
猜你喜欢
  • 1970-01-01
  • 2012-05-04
  • 1970-01-01
  • 2013-05-02
  • 2023-03-08
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-08
相关资源
最近更新 更多