为什么调用移动构造函数?
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 的复制构造函数。
鉴于我对 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 的复制构造函数。