C ++ 11复制elison和exception(catch参数)

时间:2017-03-07 16:07:54

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

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

  

当处理异常时,如果catch子句的参数与抛出的异常对象具有相同的类型(忽略顶级cv限定),则省略该副本并且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

测试用例无效或我对副本省略的理解错误吗? 非常感谢你的帮助

1 个答案:

答案 0 :(得分:3)

  
    

当处理异常时,如果catch子句的参数与抛出的异常对象的类型相同(忽略顶级cv-qualification),则省略该副本...

  

关于cppreference的措辞过于强烈。这是一个复制省略允许的案例列表。这应该是:“副本可以省略。”

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

标准(草案)的相关引用:

  

[class.copy.elision] / 1

     

......在下列情况下(允许合并以消除多份副本),允许复制/移动操作(称为复制省略)的省略:

     

[class.copy.elision] / 1.3

     

当异常处理程序的异常声明(Clause [except])声明一个相同类型的对象(cv-qualification除外)作为异常对象时,可以通过将异常声明视为异常声明来省略复制操作如果除了为exception-declaration声明的对象执行构造函数和析构函数之外,程序的含义将保持不变,则为异常对象的别名。 [注意:不能从异常对象移动,因为它始终是左值。 - 结束说明]