首先,什么是左值、右值?
左值是能出现在等号左边和右边的变量,右值是只能出现在等号右边的变量(或表达式)。
左值引用为 & , 而右值引用为 &&。
那么为什么需要右值引用呢?主要是为了处理c++临时对象的低效的问题,使用右值引用可以减少不必要的拷贝构造。
举个例子:
#include <iostream>
using namespace std;
class A {
public:
A(int a) {
cout << "constructor" << endl;
this->num = new int(a);
}
A(const A& t) {
cout << "copy" << endl;
this->num = new int(*(t.num));
}
int* num;
};
A get_A() {
A a(10);
return a;
}
int main() {
A test = get_A();
}
输出结果为:
constructor
copy
copy
调用了两次拷贝构造函数(一次用在临时变量的拷贝,一次用在test的拷贝)。使用g++可能会得到不同的输出,因为g++对此进行了优化,需要使用参数-fno-elide-constructors。
那么我们通过实现多一个函数A(A&& t)来使用右值引用:
class A {
public:
A(int a) {
cout << "constructor" << endl;
this->num = new int(a);
}
A(const A& t) {
cout << "copy" << endl;
this->num = new int(*(t.num));
}
A(A&& t) {
cout << "move" << endl;;
this->num = t.num;
}
int* num;
};
A get_A() {
A a(10);
return a;
}
int main() {
A test = get_A();
}
输出结果为:
constructor
move
move
可以看到,使用右值引用,避免了不必要的拷贝构造,而只是将资源(此处为num变量)的归属做了调整。
另外,我们还可以使用std::move()函数将左值变为右值来避免拷贝构造。
class A {
public:
A(int a) {
cout << "constructor" << endl;
this->num = new int(a);
}
A(const A& t) {
cout << "copy" << endl;
this->num = new int(*(t.num));
}
A(A&& t) {
cout << "move" << endl;;
this->num = t.num;
}
int* num;
};
A get_A() {
A a(10);
return a;
}
int main() {
A test(10);
A b(test);
A c(std::move(test));
}
输出结果为:
constructor
copy
move