1. 引用

引用(Reference) 是一个已存在变量的别名,它提供了一种更方便的方式来间接访问变量,语法为类型 &别名 = 变量名;:

int num = 10;
int& ref = num;    // ref 是变量 num 的别名

1.1 引用的注意事项

1. 引用必须在定义的时候初始化。

int& ref;               // 错误操作

2. 引用不能再绑定其它变量。

int num1 = 10, num2 = 20;
int& ref = num1;

ref = num2;    // 这个操作是把 num2 的值赋给 num1,而不是让ref成为num2的引用

1.2 常引用

常引用(Const Reference) 是指向常量的引用,使用const关键字修饰,语法为const 类型 &常引用名 = 变量名/常量名。

int num = 10;
const int& const_ref = num;
  • 即使常引用指向的是变量,也不允许通过引用对其进行修改。

2. 左值与右值


2.1 左值

左值(lvalue):具有持久内存地址的表达式;一般来说,变量、数组元素、对象成员都是左值:

int num = 10;          // num 是左值
int* ptr = #       // ptr 是左值

2.2 右值

右值(rvalue):没有持久内存地址的临时表达式,它们通常是字面量、临时对象或者函数的返回值。

  • rvalue的r是right的意思,因为在赋值表达式中 右值 只能出现在赋值号的右边。
int result = 10 + 20;   // 10、20、10+20的中间结果都是右值

2.3 左值与右值的区分

1. 寻址层面: 左值具有内存地址,可以通过取地址符&来获取其地址,而右值不可以:

int num = 10;
int* ptr1 = #         // 可以获取左值的地址
int* ptr2 = &10;          // 不可以获取右值的地址

字符串字面量是一个左值,可以取地址。

其地址在.rodata段:

auto* p = &"Hello world!";

2. 临时对象层面

函数的形参是左值:

void func(int x)
{
    int *ptr = &x;
}

func(10);

10本身是右值,但是在当参数传入func后的x是左值,相当于有一步int x = 10;

函数返回会产生临时对象,临时对象是右值:

int x = 1;

int get_x()
{
    return x;
}

x本身是左值,但是int get_x()函数返回的是x的临时副本,是一个右值。

注: 1) 现代编译器普遍支持返回值优化(RVO)和具名返回值优化(NRVO),直接在接收方的内存空间构造对象,省略拷贝过程。

std::string build_str()
{
    std::string s = "Hello world";
    return s;
}

// 调用函数,直接在接收方构造对象
std::string hello_str = build_string();

2) 不能返回函数内部局部变量的指针或引用,局部变量会在函数结束后被销毁,进而会产生野指针或悬空引用。

int& bad_return()
{
    int a = 10;
    return a;
}

3. 左值引用与右值引用

我们前面所讲的单个&的引用都是左值引用,右值引用在 C++11 中引入,使用两个&&表示,语法为类型 &&右值引用名 = 右值表达式;。

int&& rvalue_ref = 10;    // rvalue_ref 是一个右值引用

引用后的变量本身是左值,右值引用只是一个类型修饰符,表示它只能绑定到右值。


3.1 非常量左值引用与常量左值引用

1. 非常量的左值引用绑定对象只能是左值

int num = 10;
int& a = num;       // 正确,a 是 num 的左值引用
int& b = 10;        // 错误,不能将非常量左值引用绑定到右值

2. 常量左值引用允许绑定到右值,同时会延长右值的生命周期

const int& const_ref = 10;      // 正确,const_ref 是一个常量左值引用,可以绑定到右值

// 绑定后 const_ref 就像一个正常的左值一样,可以使用它来访问右值的值
// 但是由于常量语义的存在,无法进行修改

3.2 常量右值引用

常量右值引用语法正确,但基本无意义

const int&& const_rvalue_ref = 10;      // 正确,但无意义