左值引用和右值引用
左值引用
左值引用就是左值的别名,不是变量的别名,而是地址的别名,是与地址建立的一种映射关系。我们可以通过不同的别名访问同一块地址空间。
左值引用并非对象,只是为一个已经存在的对象所起的另外一个名字。
左值引用必须初始化,因为无法令左值引用重新绑定到另外一个对象。一旦初始化完成,左值引用将和他的初始值对象一直绑定在一起。
#include <iostream>
int main()
{
    int x = 1;
    int &y = x;
    // output: 0x7ffc224801bc 0x7ffc224801bc
    std::cout << &x << " " << &y << std::endl;
}
右值引用
右值引用是 C++11 为了实现移动语义(move semantic)和完美转发(perfect forwarding)而设计出来的新的数据类型。
右值引用,简单说就是绑定在右值上的引用,右值引用必须立即进行初始化操作,且只能使用右值进行初始化。
右值引用就是临时对象的别名,绑定到没有名字、即将被销毁的实体,并延长其生命周期,这为高效的资源移动提供了可能。
int && a = 10;
和常量左值引用不同的是,右值引用是一个变量,右值变量是一个左值,它有固定的内存地址,所以可以对右值进行”修改”:
int && a = 10;
a = 100;
// output: 100
cout << a << endl;
等价于
// 10是一个字面量,它本身没有内存。为了让引用a能绑定到一个实体,编译器会在栈上创建一个匿名的临时变量,并将10的值存储在这个临时变量中。
int _temp = 10;
int && a = _temp;
_temp = 100;
那么int && a = 10和int a = 10,其中a都是左值,有什么区别呢:
- int a = 10遵循值语义,10是放到了a所指向的内存。
- int && a = 10遵循引用语义,a本身不是一个对象,它只是一个别名,指向了另外一个对象。只是这个对象是临时的匿名对象。a的存在是延长这个临时对象的生命周期。