C++ 右值引用与move语义
这是一篇关于讲解关于c++左值与右值的使用问题,在c++98之前,左值与右值的概念就存在,但c++11与c++98的左值与右值有较大区别,c++11细化了值类别的概念。
1.c++中的左值与右值
左值:出现在赋值表达式左边的值被称之为左值 右值:出现在赋值表达式右边的值被称之为右值 -\ [ * ] 在c++中有一个被广泛认同的说法,具名可以寻址的值就是左值,不具名不可寻址的值就是右值
2.c++11中右值的细分(右值 = 将亡值 + 纯右值)
纯右值:与c++98中的标准右值一样,类似地,比如非引用返回的函数返回的临时对象就是一个纯右值,常量表达式产生的临时对象就是一个纯右值,类型转换函数的返回值也是纯右值,lambda表达式也是一个纯右值 将亡值:是c++11新增的与右值引用相关的表达式,比如返回右值引用类型的函数返回值,std::move()的返回值等等
2.1右值引用
右值引用就是一个对右值进行引用的类型
c++T&& value = getValue()
假设getValue返回一个右值,正常情况下,当getValue函数返回时,该右值的生命周期也就结束,而通过右值引用的显示声明,该右值的生命周期被延长,延长至和右值引用a相同的生命周期,只要a没被释放,该函数返回的右值就继续存在。
2.2使用右值引用的意义
使用传统返回,需要做的操作是,在赋值给新对象时,进行新对象的构造,函数结束之后需要进行临时对象的析构,而使用右值引用,因为a是右值引用,直接绑定到了返回的临时对象,所以不需要执行拷贝构造。 -\ [注意] a被声明为一个右值引用的前提是函数getValue()的返回值是一个右值,一般情况右值引用是不能绑定到左值
2.3万能引用
T &e = getValue(); //编译时错误
const T &f = getValue(); //不会导致编译时错误
常量左值引用在c++98中开始就是个万能引用类型,可以接受非常量左值,常量左值,右值对其进行初始化。而且在使用右值对其初始化的时候常量左值引用还可以像右值一样将右值的声明周期延长,但是在余生只能是const的
3.std::move:强制转换为右值
在c++11中,标准库
中提供函数std::move()可以将左值强制转换为右值引用,继而使用右值引用接收该值并使用。
#include
using namespace std;
class Moveable {
public:
Moveable() :i(new int(3)) {
}
~Moveable() {
delete i;
}
Moveable(const Moveable& m) :
i(new int(*m.i)) {
}
Moveable(Moveable&& m) {
m.i = nullptr;
}
int* i = 0;
};
int main() {
Moveable a;
Moveable c(move(a)); //调用移动拷贝构造函数
cout << *a.i << endl; //在移动构造函数中修改了a.i的值,因此运行在这里时报错
}
-\ [注意] 被std::move转换的对象,生命周期永远和原来保持一直,不会因为左右值的改变而改变