代码之家  ›  专栏  ›  技术社区  ›  Yaniv K.

由VLAUE返回的C++复制const激活

  •  0
  • Yaniv K.  · 技术社区  · 5 年前

    我没能找到以下问题的具体答案:

    考虑以下代码:

    Obj f() {
        Obj o2;
        return o2;
    }
    
    int main() {
        Obj o1 = f();
        return 0;
    }
    

    复制构造函数激活了多少次 没有编译器优化 ?

    万一有 移动构造函数,不是一次复制o2到调用函数,另一次构造o1吗?

    万一有 move构造函数,是不是一次将o2复制到调用函数,另一次构造o1(第二次是move const)?

    0 回复  |  直到 5 年前
        1
  •  2
  •   bolov    5 年前

    在C++ 17之前,是的,有两个复制构造函数调用(即使它们都有副作用,它们都可以被省略)。你可以看到这个 -fno-elide-constructors 在gcc/叮当声中。

    f (这一点也可以省略)。


    准确地说,它们都是动作,而不是复制品。

        2
  •  4
  •   Brian Bi    5 年前

    C++ 03与以前

    Obj return 语句(构造返回值),并进行一次初始化 o1

    如果 目标 有一个可用的移动构造函数,它被移动两次,复制零次。这个 返回 语句必须使用move,即使返回的表达式是左值。由于语言中的特殊规则,这种“移动优化”是强制性的; o2 氧1 已初始化。

    如果 目标 如果没有移动构造函数或隐式删除了移动构造函数,则会使用复制构造函数两次。

    如果 目标 有一个显式删除的移动构造函数,自 氧1 尝试使用已删除的移动构造函数。

    C++ 17及以后

    如果 目标 有一个可用的移动构造函数,当 返回 语句被执行。如上所述,编译器必须使用move而不是copy。建筑 氧1 既不涉及副本 一个动作。更确切地说 返回 中的语句 f() 初始化 氧1 ,而不是临时的。这是因为“保证的副本省略”:即使禁用了优化,语言也要求省略副本。这是因为 f() 是prvalue,而prvalue没有具体化( 实例化为临时对象),除非有必要这样做。标准所创造的“法律虚构”是 f() 实际上返回一个创建 目标 目标 氧1 f ,和 语句构造 目标 插入此指针。

    如果 目标 已隐式删除或不存在,则复制构造函数将由 返回 语句,所以将有一个副本和零移动。

    如果 目标 显式删除,程序不正确,如在C++ 11/C++ 14中。

    在所有情况下

    上述情况下的拷贝/移动可以优化。在涉及多个复制/移动操作的情况下,编译器可以优化其中的任何一个或所有操作。