0、传统的左值引用是这样的:
int a = 123;
int &b = a; // 定义一个左值引用变量
b = 456; // 通过左值引用修改引用内存的值
1、如何理解左值引用呢?
- 在汇编视角,都是指针
- 在编译器视角,左值引用只是一个别名(用于告诉编译器,这个别名跟被引用的变量的地址是同一个,更多的为了方便使用)
- 既然左值引用是别名,那么它在编译期间就必须得明确等价于某个地址。这样要求,定义左值引用时,要求右边的值必须可以取地址
int &a = 10
这种定义是无法编译报错的。
因为10是立即数,只是在计算过程中,临时存在于寄存器中,没有内存地址。
而没有内存地址,意味着编译器碰到这句话,将无法用引用替换别名a
const int &a = 10
这种定义是ok的。
因为常量是在静态存储区,加载的时候就会在内存中分配其地址
2、如何理解右值引用?
- 解决常量引用只能读取,不能修改的问题
约定俗称的定义:
左值:可以取地址的,有名字的,非临时的
右值:不能取地址的,没有名字的,临时的
从本质上理解:
1、创建和销毁由编译器幕后控制,程序员只能确保在本行代码有效的,就是右值(比如,立即数,函数返回的值等都是右值)
2、由用户创建,通过作用域规则确定生命周期的,就是左值(比如,非匿名对象或变量,函数返回的引用,const对象等)
定义右值引用的格式如下:
类型 && 引用名 = 右值表达式;
说明:
右值引用是C++ 11新增的特性,所以C++ 98的引用为左值引用
右值引用用来绑定到右值
绑定到右值以后本来会被销毁的右值的生命周期会延长至与绑定到它的右值引用的生命周期
右值引用的存在并不是为了取代左值引用,而是充分利用右值(特别是临时对象)的构造来减少对象构造和析构操作以达到提高效率的目的
移动构造函数
带右值引用参数的拷贝构造和赋值重载函数,又叫移动构造函数和移动赋值函数
这里的移动指的是把临时量的资源移动给了当前对象,临时对象就不持有资源,为nullptr了
实际上没有进行任何的数据移动,没发生任何的内存开辟和数据拷贝
参考:https://zhuanlan.zhihu.com/p/97128024