4

经过代码审查后,我们在 try/catch 块中遇到了复制 elison 的问题。阅读本页后: cpp 参考指南,尤其是本段:

处理异常时,如果 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

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

4

1 回答 1

3

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

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

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


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

[class.copy.elision] / 1

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

[class.copy.elision] / 1.3

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

于 2017-03-07T16:32:57.653 回答