1.C++中左值与右值得定义
- 左值(lvalue, locator value):存储在内存中,由明确的存储地址的数据,能够对其地址进行操作。(左值引用的目的是防止函数在进行传参和返回值的时候进行对象的拷贝)
- 右值(rvlaue, read value):指的是哪些不可以对其地址进行操作的数据(如寄存器中的数据)右值分为纯右值和将亡值,纯右值比如字面值、返回非引用类型的函数调用、后置自增/自减等。(右值引用它的主要目的有两个方面:消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。能够更简洁明确地定义泛型函数。)
- C++中的表达式,不是左值就是右值,左值可以位于赋值语句的左侧/也可以位于右侧,而右值则不能。当一个对象被用作右值的时候,用的是对象的值;当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。需要右值的地方可以用左值代替,但不能把右值当成左值使用。
将亡值
- 将亡值是C++11引入的一种新的引用类型,用于支持移动语义的实现;
- 在C++中,表达式具有值的属性,可以分为左值和右值。左值是可以标识的、持久的对象,而右值是临时的、匿名的、即将被销毁的对象。
- 将亡值是一种特殊的右值引用类型,表示一个即将要被移动的对象或资源。通过将亡值引用,可以实现高效的资源转移,而不需要进行深拷贝的操作。
- 将亡值引用的语法是通过在类型后加上 && 运算符来定义。例如,int&& 表示一个将亡值引用,可以绑定到一个右值。
- 将亡值引用通常在移动构造函数和移动赋值运算符中使用,用于从一个对象转移资源到另一个对象,而不需要进行资源的赋值操作。这样可以显著提高程序性能和效率。
2.引用是为对象起的别名、必须被初始化、通过引用修改变量。
左值引用
左值引用就是对左值的引用,我们平常使用的“引用”。我们通过 & 来获得左值引用,可以把引用绑定到一个左值上,而不能绑定到要求转换的表达式、字面常量或是返回右值的表达式。
int i{0};
int &p = i;//这里是一个左值引用,相当于给i起了一个别名
int &p1 = i + 1;//错误,i+1是一个临时变量为右值,不能对其地址操作
const int &p2 = i +1;//正确,可以将一个const的引用绑定到一个右值上
虽然常量左值引用可以引用右值的这个特性在赋值表达式中看不出什么实用价值,但是在函数形参列表中却有着巨大的作用。请参考《现代C++语言核心特性分析》。
右值引用
右值引用就是必须绑定到右值的引用,他有着与左值引用完全相反的绑定特性,我们通过 && 来获得右值引用。这里可以理解为给一个没有地址的右值一个名字。(应用场景:移动拷贝构造函数)
int i{0};
int &&p = i + 1;
引入右值引用的原因
(1)替代需要销毁对象的拷贝,提高效率:某些情况下,需要拷贝一个对象然后将其销毁,如:临时类对象的拷贝就要先将旧内存的资源拷贝到新内存,然后释放旧内存,引入右值引用后,就可以让新对象直接使用旧内存并且销毁原对象,这样就减少了内存和运算资源的使用,从而提高了运行效率;
(2)移动含有不能共享资源的类对象:像IO、unique_ptr这样的类包含不能被共享的资源(如:IO缓冲、指针),因此,这些类对象不能拷贝但可以移动。这种情况,需要先调用std::move将左值强制转换为右值,再进行右值引用。
三、右值引用与左值引用的区别
(1)左值引用绑定到有确定存储空间以及变量名的对象上,表达式结束后对象依然存在;右值引用绑定到要求转换的表达式、字面常量、返回右值的表达式等临时对象上,赋值表达式结束后就对象就会被销毁。
(2)左值引用后可以利用别名修改左值对象;右值引用绑定的值不能修改。
参考:
https://blog.csdn.net/kk702392702/article/details/129415575
理解 C/C++ 中的左值和右值
https://nettee.github.io/posts/2018/Understanding-lvalues-and-rvalues-in-C-and-C/
https://blog.csdn.net/weixin_51795597/article/details/135989208?utm_medium=distribute.pc_relevant.none-task-blog-
将亡值与移动语义:https://blog.csdn.net/weixin_51795597/article/details/135989208
C++高级特性:
https://blog.csdn.net/weixin_43808717/article/details/137657788