左值和右值的概念及其使用方法
前言
本文章详细讲解左值和右值的概念和使用方法,即展示了它的应用场景:移动语义和完美转发
一、什么是左值?什么是右值?
在C++中,所有的值不是左值,就是右值。左值是指表达式结束后依然存在的持久化对象,右值是指表达式结束后就不再存在的临时对象。有名字的对象都是左值,右值没有名字。
还有一个可以区分左值和右值的便捷方法:看能不能对表达式取地址,如果能,则为左值,否则为右值。
C++11扩展了右值的概念,将右值分为了纯右值和将亡值。
纯右值:a)非引用返回的临时变量;b)运算表达式产生的结果;c)字面常量(C风格字符串除外,它是地址)。
将亡值:与右值引用相关的表达式,例如:将要被移动的对象、T&&函数返回的值、std::move()的返回值、转换成T&&的类型的转换函数的返回值。
不懂纯右值和将亡值的区别其实没关系,统一看作右值即可,不影响使用。
直接代码演示:
class AA
{
int m_aa;
};
AA getaa()
{
return AA();//返回一个匿名AA类的对象
}
int a = 3;//此时a是左值,3是右值
int b = a + 4;//b是左值,a+4是右值
AA aa=getaa();//aa是左值,getaa返回的AA的对象是临时变量,是右值
二、左值引用和右值引用
1.左值引用
左值引用就是给左值取一个名字
语法:数据类型 &变量名 = 左值;
代码演示,文字不好表述。
#include <iostream>
using namespace std;
int main()
{
int a = 3;//a是左值,3是右值
int &b=a;//等于号右边必须是左值
//int &b=3;因为3是右值,所有这段代码错误
}
2.右值引用
C++98中的引用很常见,就是给变量取个别名,在C++11中,因为增加了右值引用(rvalue reference)的概念,所以C++98中的引用都称为了左值引用(lvalue reference)。
右值引用就是给右值取个名字。
语法:数据类型&& 变量名=右值;
代码演示:
#include <iostream>
using namespace std;
class AA {
public:
int m_a=9;
};
AA getTemp()
{
return AA();
}
int main()
{
int&& a = 3; // 3是右值。
int b = 8; // b是左值。
int&& c = b + 5; // b+5是右值。
AA&& aa = getTemp(); // getTemp()的返回值是右值(临时变量)。
cout << "a=" << a << endl;
cout << "c=" << c << endl;
cout << "aa.m_a=" << aa.m_a << endl;
}
getTemp()的返回值本来在表达式语句结束后其生命也就该终结了(因为是临时变量),而通过右值引用重获了新生,其生命周期将与右值引用类型变量aa的生命周期一样,只要aa还活着,该右值临时变量将会一直存活下去。
引入右值引用的主要目的是实现移动语义。
三、常量引用
左值引用只能绑定(关联、指向)左值,右值引用只能绑定右值,如果绑定的不对,编译就会失败。
但是,常量左值引用却是个奇葩,它可以算是一个万能的引用类型,它可以绑定非常量左值、常量左值、右值,而且在绑定右值的时候,常量左值引用还可以像右值引用一样将右值的生命期延长,缺点是,只能读不能改。大家可能无法理解,直接上代码演示:
语法:const 数据类型 &变量名=左值/右值;
int a = 1;
const int& ra = a; // a是非常量左值。
const int b = 1;
const int& rb = b; // b是常量左值。
const int& rc = 1; // 1是右值。
//在数据类型前面加入const就可以绑定右值
这种在函数传递参数时用的比较频繁,直接演示:
#include <iostream>
using namespace std;
void fun(int& a)
{
cout << "a=" << a << endl;
}
int main(int argc, char* argv[])
{
//fun(2);这段代码错误,因为函数体内是左值引用,只能绑定左值
//2是右值,所以编译器会报错
return 0;
}
会出现以下错误:
如果传一个左值就不会报错
加入const后会解决这种问题
#include <iostream>
using namespace std;
void fun(const int& a)
{
cout << "a=" << a << endl;
}
int main(int argc, char* argv[])
{
fun(2);//这段代码不会报错,因为函数体内是常量左值引用,既可以绑定右值,也可以绑定左值
return 0;
}
注意只能是常量左值引用,不能是常量右值应用。
总结一下,其中T是一个具体类型:
1)左值引用, 使用 T&, 只能绑定左值。
2)右值引用, 使用 T&&, 只能绑定右值。
3)已命名的右值引用是左值。
4)常量左值,使用 const T&, 既可以绑定左值又可以绑定右值。
总结
本文章介绍了什么是左值,什么是右值和左值引用和右值引用。它在与函数传参和移动语义有很大的作用。移动语义后面再介绍。
标签:AA,右值,int,左值,绑定,概览,引用 From: https://blog.csdn.net/2301_76771136/article/details/144130728