移动构造函数在下面显示的代码段中是否有任何特殊原因?

Bel*_*loc 14 c++ exception copy-elision c++14

抛出对象后,gcc,clang和VS2015不会在下面的代码中忽略对move构造函数的调用a.在我看来,满足§8.12[class.copy]/31(N4140)的项目符号(31.2)中确定的条件.

#include <iostream>

struct A
{
    A() { std::cout << "Default ctor " << '\n'; }
    A(const A& a) { std::cout << "Copy ctor" << '\n'; }
    A(A&& a) { std::cout << "Move ctor" << '\n'; }
    ~A() { std::cout << "Destructor " << '\n'; }
};

int main()
{
    try
    {
        A a;
        throw a;
    }
    catch(A& a) { std::cout << "Caught" << '\n'; }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这a是一个左值,但根据§12.8/ 32,首先执行重载决策以选择副本的构造函数,就像对象由rvalue指定一样.也就是说,对move构造函数的调用是可以的.如果删除上面的移动构造函数的定义,则调用复制构造函数,但同样,它不会被省略!

我理解标准没有规定复制省略,但我很想知道是否有任何特殊条件可以证明这一事实,上面提到的三个编译器在这个特定的例子中避免了这种优化.

gcc的示例输出,来自上面的链接:

g ++ -std = c ++ 14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

默认ctor

移动ctor

析构函数

抓住

析构函数

Die*_*ühl 3

根据 12.8 [class.copy] 第 31 段,第二个项目符号,可以省略被抛出的局部变量的副本:

throw 表达式中,当操作数是非易失性自动对象(函数或 catch 子句参数除外)的名称时,其作用域不超出最内层封闭try 块的末尾(如果有一个),通过将自动对象直接构造到异常对象中,可以省略从操作数到异常对象(15.1)的复制/移动操作

似乎没有一个编译器使用这种优化。原因之一可能是,只要将精力花在其他优化上更好,就根本不值得这样做。我认为标准中没有任何内容禁止这种优化。