使用仅使用一次的变量调用的复制构造函数。这可能是通过调用移动构造函数来优化编译器的情况吗?

Copy constructor called with a variable used only once. Could this be a case for compiler optimization by calling the move constructor instead?

代码:

#include <iostream>

class A {
public:
    A() {
    }

    A(const A& a) {
        std::cout << "Copy constructor" << std::endl;
    }

    A(A&& a) {
        std::cout << "Move constructor" << std::endl;
    }
};

int main()
{
    {//case 1
        A b = A(A());
    }
    std::cout << std::endl;
    {// case 2
        A a;
        A b = A(a);
    }
    std::cout << std::endl;
    {//case 3
        A a;
        A b = A(std::move(a));
    }
}

输出(带有-O3编译标志):

#case 1
#nothing printed

#case 2
Copy constructor

#case 3
Move constructor

对于情况2,为什么即使使用最大优化级别(-O3) 也会调用复制构造函数? 我期望编译器检测到变量 'a' 就像是临时变量(因为仅用于 'b' 的构造),而是使用移动构造函数(如案例 3)。

据我所知,至少有一种情况(return 值优化)编译器可以通过避免调用具有副作用的复制构造函数来改变程序的可观察行为。
所以我想知道在情况 2 中是否有可能,同样出于优化目的,用移动构造函数替换复制构造函数的调用,知道变量 a 永远不会在 b 的构造之外使用。

虽然可以得到一个没有名字的临时左值(见这个 question),但这里不是这样。

在情况 2 中,a 不是临时的而是命名的左值,因此不会发生省略并调用复制构造函数。

To my knowledge there is at least one case (return value optimization) where the compiler can alter the observable behavior of the program by avoiding the call to a copy constructor which has side effect.

标准明确指定了这些情况,不幸的是,不包括像您的情况 2 这样的情况,因此不允许编译器执行此类改变可观察行为的优化。


标准中的相关部分 [class.copy.elision]/3:

In the following copy-initialization contexts, a move operation might be used instead of a copy operation:

  • If the expression in a return statement ([stmt.return]) is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, or

  • if the operand of a throw-expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one),