在下面的代码片段中没有省略move构造函数有什么特殊的原因吗?

Is there any special reason why the move constructor is not elided in the snippet shown below?

本文关键字:什么 构造函数 片段 代码 在下面 move      更新时间:2023-10-16

gcc, clang和VS2015在抛出对象a之后不会忽略对下面代码中的move构造函数的调用。在我看来,§8.12[类]的要点(31.2)所确立的条件。copy]/31 (N4140)

#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,过载分辨率首先执行为副本选择构造函数的操作,就好像对象是由右值指定的一样。也就是说,调用move构造函数是可以的。如果删除上面move构造函数的定义,则调用复制构造函数,但同样没有省略它!

我知道copy-省略不是标准强制要求的,但是我很想知道是否有任何特殊的条件可以证明,在这个特定的例子中,上面提到的三个编译器避免了这种优化。

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

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

默认男星

移动男星

析构函数

析构函数

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

throw表达式中的

,当操作数是非易失性自动对象(函数或catch子句参数除外)的名称时,该对象的作用域没有扩展到最内层的末尾包含try-block(如果有的话),通过将自动对象直接构造为异常对象

,可以省略从操作数到异常对象(15.1)的复制/移动操作。

似乎没有一个编译器使用这种优化。一个原因可能是,只要把精力花在其他优化上,就不值得这么做。