左值和右值
在C++11中所有的值必属于左值、右值两者之一。
左值:表示的是可以获取地址的表达式,它能出现在赋值语句的左边,对该表达式进行赋值。但是修饰符const的出现使得可以声明如下的标识符,它可以取得地址,但是没办法对其进行赋值。
const int& a = 10;
右值:表示无法获取地址的表达式,有常量值、函数返回值、lambda表达式等(都是临时对象)。无法获取地址,但不表示其不可改变,当定义了右值的右值引用时就可以更改右值。
左值引用和右值引用
左值引用:传统的C++中引用被称为左值引用,作用是起别名(绑定)。
右值引用:C++11中增加了右值引用,右值引用关联到右值时,右值被存储到特定位置,右值引用指向该特定位置。也就是说,右值虽然无法获取地址,但是右值引用是可以获取地址的,该地址表示临时对象的存储位置。
右值引用的特点
- 特点1:通过右值引用的声明,右值又“重获新生”,其生命周期与右值引用类型变量的生命周期一样长,只要该变量还活着,该右值临时量将会一直存活下去。
- 特点2:右值引用独立于左值和右值。意思是右值引用类型的变量可能是左值也可能是右值。
- 特点3:右值值引用通常不能绑定到任何的左值,要想绑定一个左值到右值引用,通常需要std::move()将左值强制转换为右值。
- 特点4:
T&& t
在发生自动类型推断的时候,它是左值还是右值取决于它的初始化。
一些例子:
#include <bits/stdc++.h>
using namespace std;
template<typename T>
void fun(T&& t)
{
cout << t << endl;
}
int getInt()
{
return 5;
}
int main() {
int a = 10;
int& b = a; //b是左值引用
int& c = 10; //错误,c是左值不能使用右值初始化
int&& d = 10; //正确,右值引用用右值初始化
int&& e = a; //错误,e是右值引用不能使用左值初始化
int&& e = std::move(a); //正确,a强制转换为右值之后可以初始化
const int& f = a; //正确,左值常引用相当于是万能型,可以用左值或者右值初始化
const int& g = 10;//正确,左值常引用相当于是万能型,可以用左值或者右值初始化
const int&& h = 10; //正确,右值常引用
const int& aa = h;//正确
int& i = getInt(); //错误,i是左值引用不能使用临时变量(右值)初始化
int&& j = getInt(); //正确,函数返回值是右值
fun(10); //此时fun函数的参数t是右值
fun(a); //此时fun函数的参数t是左值
return 0;
}
C++11右值引用目的、作用好处:
引入右值引用的主要目的是提高程序运行效率。有些对象在复制时需要进行深复制(拷贝),深拷贝往往非常耗时。合理使用右值引用可以避免深复制操作。
右值引用通过减少内存的重复申请、拷贝和释放,有效的提高C++程序的性能。