左值、右值 、左值引用、右值引用的总结


在C语言中我们常常会提起左值(lvalue) 和 右值(rvalue) 这样的称呼。编译器在编译程序报错时, 有时也会报出错误信息中会包含左值、右值的说法。但是左值和右值并没有一个严谨的定义。大多数时候左右值的定义与其判别方法是一体的。
一个典型的的判别方法就是,在赋值表达式中。出现在等号左边的就是 左值,而在等号右边的,则称为 右值
例如:
a = b + c;
在这个赋值表达式中,a就是一个左值,而b+c则是一个右值。这种识别左值、右值的方法在C++中依然有效。
不过C++中还有一个被广泛认同的说法,那就是 可以取地址的、有名字的就是左值,反之 , 不能取地址的、没有名字的就是右值
在这个赋值表达式中,&a是运行的操作。但是&(b+c) 这样的操作则不会通过编译。因此 a 是一个左值, (b+c) 是一个右值。

什么是左值

可以和按照C++上的说法:可以取地址的、有名字的就是左值。

什么是右值

不能取地址的、没有名字的就是右值。具体在C++11中,右值是由两个概念构成的。
一个是将亡值。一个是纯右值。

纯右值:

纯右值(prvalue, Pure Rvalue)就是C++98标准中的右值概念,比如函数返回的临时变量值。还有一些运算表达式,比如 1 + 3 产生的临时变量值。
不跟对象关联的字面量值,比如:2、‘c’ 、true。lambda表达式 。都是纯右值。

将亡值:

将亡值 (xvalue, eXpiring) 是C++11中新增的跟右值引用相关的表达式。这样的表达式通常是将要被移动的对象(移为他用)。
比如:返回右值引用 T&& 的函数返回值;std::move的返回值; 转换为T&&的类型转换函数的返回值。

:在C++11的程序中,所有的值必属于左值、将亡值、纯右值三者之一。

左值引用

左值引用就是C++98中的引用 T&。在没出来C+11的右值引用之前。说的引用都是指的左值引用。
例如:
int a = 10;
int & b = a;
const int & c = a;
b和c都是 左值引用。b是非常量左值引用。c是常量左值引用。
左值引用顾名思义就是对一个左值进行引用的类型。也就是等号右侧的是一个左值(可取地址的)。
而常量左值引用类型 比较特殊,也可以对右值进行引用。如 const int &d = 2; 但是 int &d = 2;是编译不过的。
因此常量左值引用类型也称为万能的引用类型。通过常量左值引用不可以修改所引用的内容。而 非常量左值引用可以修改引用的内容。

右值引用

右值引用是C++11中新增的一种引用类型,顾名思义就是对一个右值进行引用的类型。事实上,由于右值不具有名字。我们也只能通过引用的方式找到的它的存在。
例如:T && a = ReturnRvalue();
这个表达式中,假设ReturnRvalue函数返回一个右值,我们就声明了一个名为a的右值引用,其值等于ReturnRvalue函数返回的临时变量的值。
注意: T&& 就是 右值引用的类型。与左值引用比较多了个 &符号。和二级指针的使用方式 不一样。C++上不存在二级引用。
注意:引用 也是一个变量,不过是一种特殊的变量,拥有自己的类型。
相同点
左值引用和右值引用都是属于引用类型。
无论声明的一个左值引用还是右值引用,都必须立即进行初始化。而其原因可以理解为是引用类型本身自己并不拥有所绑定的对象的内
存,只是该对象的一个别名,几乎不占用什么内存。
不同点
左值引用是具名变量值的别名,而右值引用则是不具名(匿名)变量的别名。
右值引用是不能够绑定到任何的左值的。比如:
int c;
int && d = c;//编译不过
相对的左值引用也是不可以绑定到右值(由右值进行初始化)的。
比如:
T & e = ReturnRvalue();//编译不过。
但是存在例外:const T & e = ReturnRvalue();//编译通过。上面我们说常量左值引用是万能引用类型,它可以接收非常量左值(如:int
c),常量左值(如:const int c)、右值对其进行初始化。
右值引用类型的使用场景:用于移动构造函数的形参类型 和 移动语义紧密相关联。

猜你喜欢

转载自blog.csdn.net/adminstate/article/details/134876604