在代码审查之后,我们在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
测试用例无效或我对副本省略的理解错误吗? 非常感谢你的帮助
答案 0 :(得分:3)
当处理异常时,如果catch子句的参数与抛出的异常对象的类型相同(忽略顶级cv-qualification),则省略该副本...
关于cppreference的措辞过于强烈。这是一个复制省略允许的案例列表。这应该是:“副本可以省略。”
似乎编译器没有执行复制省略,即使它被允许。
标准(草案)的相关引用:
[class.copy.elision] / 1
......在下列情况下(允许合并以消除多份副本),允许复制/移动操作(称为复制省略)的省略:
[class.copy.elision] / 1.3
当异常处理程序的异常声明(Clause [except])声明一个相同类型的对象(cv-qualification除外)作为异常对象时,可以通过将异常声明视为异常声明来省略复制操作如果除了为exception-declaration声明的对象执行构造函数和析构函数之外,程序的含义将保持不变,则为异常对象的别名。 [注意:不能从异常对象移动,因为它始终是左值。 - 结束说明]