为什么调用移动构造函数?

Why is the move constructor being called?

鉴于我对 return 值优化的理解,我对为什么在下面的示例代码中调用移动构造函数感到困惑:

#include <vector>
#include <iostream>

class MyCustomType
{
public:
  MyCustomType()
  {
    std::cout << "Constructor called" << std::endl;
  }

  MyCustomType(const MyCustomType & inOther) : // copy constructor
    mData(inOther.mData)
  {
    std::cout << "Copy constructor called" << std::endl;
  }

  MyCustomType(MyCustomType && inOther) : // move constructor
    mData(std::move(inOther.mData))
  {
    std::cout << "Move constructor called" << std::endl;
  }

private:
  std::vector<int> mData;
};

MyCustomType getCustomType()
{
  MyCustomType _customType;
  return _customType;
}

int main()
{
  MyCustomType _t = getCustomType();
}

输出:

Constructor called
Move constructor called

我假设只会构造一个 MyCustomType 实例并将其直接分配给 _t

有关信息,我使用的是 VC14 编译器。

在您的示例中,您假设将应用 NRVO。但是NRVO只是一个优化,不能保证被编译器使用^.

我已经用 http://webcompiler.cloudapp.net/ 测试了你的例子。

默认的编译器选项集是:

/EHsc /nologo /W4

在这种情况下,输出与您的相似:

Constructor called

Move constructor called

但是如果使用 /O2 标志启用适当的优化:

/O2 /EHsc /nologo /W4

则输出为:

Constructor called

^ 正如@einpoklum 在评论中提到的那样,自 C++17 以来规则已经发生了变化。

因为表达式 getCustomType() 是一个 prvalue(rvalue),而且参数比参数更符合 cv。

为了看到"more"复制省略,可以试试release编译方式

顺便说一句,inOther.mData 没有移动,mData(std::move(inOther.mData)) 实际上会调用 vector 的复制构造函数。