复制省略和例外

Pum*_*kko 6 c++ exception copy-constructor

在阅读了关于cppreference的复制省略后,我想玩异常和复制省略.所以我在coliru上用gcc 7.2编写了以下代码

#include <iostream>

class Exception
{
public:
    Exception() { std::cout << "constructed\n"; }
    Exception(Exception& other) {std::cout << "copy constructed\n";}
    Exception(const Exception& other) {std::cout << "copy constructed\n";}
    Exception(Exception&& other) {std::cout << "move constructed\n";}
};

void foo()
{
    throw Exception();
}

int main()
{
    try
    {
        foo();
    }
    catch(Exception e )
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

产量

构造的
复制品

我们可以看到复制构造函数被调用,即使用-O2调用gcc也会发生这种情况.在我看来,此代码应该有资格根据以下条款复制elision:

处理异常时,如果catch子句的参数与抛出的异常对象具有相同的类型(忽略顶级cv限定),则省略该副本,并且catch子句的主体直接访问异常对象,如如果被引用抓住了

那么为什么复制构造函数被调用?为什么复制省略在这种情况下不起作用?

rus*_*tyx 5

cppreference对此不准确.事实上,除了常量表达式(constexpr)或常量初始化(静态或线程局部)之外,实际上无法保证副本将被省略.在您的示例中并非如此.

请参阅当前C++ 17草案中的[class.copy.elision]/1(强调我的):

当满足某些标准时,...... 在下列情况下,允许复制/移动操作的省略,称为复制省略:

- 在throw-expression中,当操作数是非易失性自动对象的名称(函数或catch子句参数除外),其范围不会超出最内层封闭try-block的末尾(如果有的话) 1),通过将自动对象直接构造到异常对象中,可以省略从操作数到异常对象的复制/移动操作

在需要常量表达式和常量初始化的上下文中计算表达式时,需要复制省略.

这意味着有一天它可能被实现为编译器优化,但目前情况并非如此.

这将是明智因此对catch通过const&暂且(也以避免意外的切片).