为什么不调用复制构造函数?

时间:2013-05-02 17:55:35

标签: c++ reference constructor copy-constructor return-value-optimization

在此代码中:

#include <iostream>

using std::cout;

class Foo {
    public:
        Foo(): egg(0) {}
        Foo(const Foo& other): egg(1) {}

        int egg;
};

Foo bar() {
    Foo baz;
    baz.egg = 3;
    return baz;
}

int main(void) {
    Foo spam(bar());
    cout << spam.egg;
    return 0;
}

输出为3,而我预计它为1

这意味着不会在行Foo spam(bar())中调用复制构造函数。

我想这是因为bar函数没有返回引用。

您能解释一下spam初始化时的实际情况吗?

如果这是一个愚蠢的问题,我会事先道歉。

谢谢!

1 个答案:

答案 0 :(得分:17)

复制/移动elision是所谓的“ as-if ”规则的唯一允许例外,它通常限制允许编译器执行的转换(例如优化)的种类。一个程序。

该规则旨在允许编译器执行他们希望的任何优化,只要转换后的程序可以“好像”它是原始的一样。但是,有一个重要的例外。

根据C ++ 11标准的第12.8 / 31段:

  

当满足某些条件时,允许实现省略类的复制/移动构造   object,即使是为复制/移动操作选择的构造函数和/或对象的析构函数   有副作用。 [......]在下列情况下允许复制/移动操作(称为复制省略)   可以合并以消除多个副本):

     
      
  • 在具有类返回类型的函数中的return语句中,当表达式是a的名称时   具有相同cv-unqualified的非易失性自动对象(函数或catch子句参数除外)   键入函数返回类型,可以通过构造省略复制/移动操作   自动对象直接进入函数的返回值
  •   
     

[...]

     
      
  • 当复制/移动尚未绑定到引用(12.2)的临时类对象时   对于具有相同cv-unqualified类型的类对象,可以省略复制/移动操作   将临时对象直接构造到省略的copy / move
  • 的目标中   
     

[...]

换句话说,在12.8 / 31的规定适用的情况下,你不应该依赖复制构造函数或移动被调用的构造函数或