在C++中,初始化类似

MyClass(myBigObject s):
  s_(s)
{
...
}

好像s在函数入口(“按值传递”)被复制一次,并在分配给s_时被复制一次。

编译器是否足够聪明,可以删除第一个副本?

最佳答案

临时复制到s的文件可以省略

如果传递临时对象,则优化的编译器可能会省略第一个副本:

MyClass x{ myBigObject() };

由于临时myBigObject将直接构造到构造函数参数s中,因此可能仅调用一次复制构造函数。

请注意,这可以更改程序的可观察行为。
#include <iostream>

struct myBigObject
{
  size_t x;
  myBigObject() : x() {}
  myBigObject(myBigObject && other)
  {
    std::cout << "Move myBigObject" << std::endl;
  }
  myBigObject(const myBigObject &other)
  {
    std::cout << "Copy myBigObject" << std::endl;
    x = 12;
  }
};

struct MyClass
{
    MyClass(myBigObject s)
      : s_(s)
    {
      std::cout << "x of s : " << s.x << std::endl;
      std::cout << "x of s_ : " << s_.x << std::endl;
    }
    myBigObject s_;
};

int main()
{
  std::cout << "A:" << std::endl;
  MyClass x{ myBigObject() };
  std::cout << "B:" << std::endl;
  myBigObject y;
  MyClass z{ y };
}

打印(https://ideone.com/hMEv1W + MSVS2013,Toolsetv120)
A:
Copy myBigObject
x of s : 0
x of s_ : 12
B:
Copy myBigObject
Copy myBigObject
x of s : 12
x of s_ : 12

无法复制到s_中的第二个副本

由于s_s需要是不同的对象,因此不能省略复制到s_中的操作。

如果您只想在类(class)中获得一份myBigObject,可以申请:
MyClass(myBigObject const & s)
  : s_(s)
{
}
MyClass(myBigObject && s)
  : s_(std::forward<myBigObject>(s))
{
}

这样,对于临时对象,您将看不到任何副本,对于非临时对象,您将仅看到一个副本。

更改后的代码将打印:
A:
Move myBigObject
B:
Copy myBigObject

10-01 17:51