14

gcc, clang 和 VS2015 在抛出 object 之后,不会在下面的代码中省略对 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'; }
}

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

我知道标准没有强制要求复制省略,但我很想知道是否有任何特殊条件可以证明上述三个编译器在这个特定示例中避免了这种优化这一事实。

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

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

默认 ctor

移动 ctor

析构函数

抓住

析构函数

4

1 回答 1

3

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

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

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

于 2015-09-27T20:26:27.523 回答