繁体   English   中英

使用仅使用一次的变量调用的复制构造函数。 这是否可以通过调用移动构造函数来进行编译器优化?

[英]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)。

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

据我所知,至少有一种情况(返回值优化),编译器可以通过避免调用具有副作用的复制构造函数来改变程序的可观察行为。

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


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

在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:

  • 如果 return 语句 ([stmt.return]) 中的表达式是一个(可能带括号的)id 表达式,它命名一个对象,该对象具有在最内部封闭函数或 lambda 表达式的主体或参数声明子句中声明的自动存储持续时间, 或者

  • 如果 throw 表达式的操作数是非易失性自动对象的名称(函数或 catch 子句参数除外),其范围不超出最内层封闭 try 块的末尾(如果有) ,

尽管可以获得没有名称的临时左值(请参阅此问题),但这不是这里发生的情况。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM