左值引用

左值引用就是左值的别名,不是变量的别名,而是地址的别名,是与地址建立的一种映射关系。我们可以通过不同的别名访问同一块地址空间。

左值引用并非对象,只是为一个已经存在的对象所起的另外一个名字。

左值引用必须初始化,因为无法令左值引用重新绑定到另外一个对象。一旦初始化完成,左值引用将和他的初始值对象一直绑定在一起。

#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 = 10int a = 10,其中a都是左值,有什么区别呢:

  • int a = 10遵循值语义,10是放到了a所指向的内存。
  • int && a = 10遵循引用语义,a本身不是一个对象,它只是一个别名,指向了另外一个对象。只是这个对象是临时的匿名对象。a的存在是延长这个临时对象的生命周期。