移动构造函数和右值引用

Move constructors and rvalue references

本文关键字:引用 构造函数 移动      更新时间:2023-10-16
class Foo {
int m_num;
public:
Foo() {}
Foo(int& n) {m_num = n;}
Foo(int&& n) {m_num = n;}
Foo(const Foo& src) {m_num = src.m_num;}
Foo(Foo&& src) {m_num = src.m_num;}
Foo& operator =(const Foo& src) {
m_num = src.m_num;
return *this;
}
Foo& operator =(Foo&& src) {// move
m_num = src.m_num;
return *this;
}
int& operator =(const int& src) {return m_num = src;}
int& operator =(int&& src) {return m_num = src;}
};

为什么当我调用Foo f4(Foo(2));时,它调用Foo(int&& n)构造函数而不是构造函数Foo(Foo&& src)? 另外,为什么传递 num 这是一个右值引用调用移动构造函数? 例如,Foo f = num不调用移动构造函数。

int main() {
int&& num = 5;
/*int num{ 5 };*/ // initializer-list
Foo f = num; // custom constructor
f = num; // assignment operator
Foo f2 = 6; // custom move constructor
f2 = 10; // custom move assignment
f2 = f; // assignment operator
Foo f3(f); // custom constructor
// f3(f2); // ERROR
f3 = (f2); // assignment operator
Foo f4(Foo(2));

Foo(2)中,整数是一个右值,需要一个来自int&&的右值引用构造函数。

在以下情况下

Foo f = num; // custom constructor 

不调用右值构造函数,因为命名值永远不会被视为右值。您必须调用std::move(num)才能使其正常工作。

该标准以这种方式定义它,以避免在意外移动命名值并在以后使用时混淆情况。您必须明确移动,即使变量是右值引用也是如此。

编辑

根据cpp首选项,c ++ 17编译器必须省略复制/移动构造函数(即在这种情况下,它不得调用或要求存在复制/移动构造函数,这就是为什么您只能看到int&&中的构造函数(:

Foo f4(Foo(2));

这是来自cpp偏好的引用(不如标准,但足够接近(:

语言规则确保不发生复制/移动操作, 甚至在概念上:

  • 在变量的初始化中,当初始值设定项表达式 是与 变量类型:

    T x = T(T(T(T((((;//只调用一次 T 的默认构造函数,以初始化 x