引用基本概念
// 基本概念
- 引用声明:为一个已经存在的对象起一个别名,且可起多个别名。引用一经声明不可变更
- 引用只有声明没有定义,且不分配内存,引用只是一种声明,声明其与实体的关系
- 引用ref的值就是其绑定对象的值,引用ref的地址&ref就是其绑定对象的地址
- 不能声明对引用的引用,因为引用本身不是一个实体:int& ref = ref2;
- 定义一个引用后,所有对引用的操作,实际上是对绑定对象的操作
// 引用本质
- int& ref = a; // 在CPP内部相当于:int* const p = &a;
- 只要对a进行引用,就相当于定义了一个指向a的const指针
// 左值
- ++i,--i是左值表达式
// 右值
- i++,i--是右值表达式
// 左值引用
- int& ref = a;
- int a = 10; int& lef = a * 10; // 错误,左值引用不可绑定到右值上
// 右值引用
- 右值引用:希望用右值引用绑定到一些即将销毁的或者临时对象上
- int&& ref = 10; // 会产生临时变量。临时变量被当成右值
- int a = 10; int&& ref = a; // 错误,右值引用无法绑定到左值上
- int&& ref = a * 10; // 正确,右值引用绑定到右值上
- 右值引用目的:
- 提高程序运行效率:把拷贝对象变成移动对象来提高程序运行效率
- 移动对象如何产生:移动构造函数、移动赋值运算符。都需要右值引用来触发:&&
// const引用
- 可以使用任意表达式初始化const引用,只要表达式能转换成引用的类型即可
- const int& ref1 = a;
- const int& ref2 = 5;
- const int& ref3 = ref2*10;
- const既可绑定到右值,还可以绑定到左值
- const int& ref = 10;
- const int& lef = a * 10;
// 普通引用
- 可通过普通引用ref改变其绑定对象的值:int& ref =a; ref=b;
- 将普通引用绑定到const对象非法,const对象不可被修改,普通引用却可修改其绑定对象
- const int a = 10; int& ref =a; // 错误,普通引用绑定到const对象
- int& ref = 10; // 错误,普通引用绑定到字面值,即const对象
// std::move
- 功能:将一个左值转成右值:string str = "i love"; string def = std::move(str);
// 怎样引用
int& ref = x; // ref是x的别名
int& ref[10] = ...; // err,不存在引用数组
int (&ref)[10] = arr; // 引用一个具有10个int元素的数组
int* p = &a; int* & ref = p; // 对指针的引用
// 引用作函数参数
1. 好处:没有复制实参的开销,提高程序执行效率
// 引用作函数返回值
1. (int,struct)类型的变量在return语句中,直接返回一个变量,要执行复制操作
2. (int*,struct*)指针类型的变量在return语句,只做了一个地址传递,也进行了复制,但效率还是很高
3. (int&,struct&)引用引开在return语句中,代表的就是变量本身,没有复制的开销
4. 引用作为函数返回值,则要求返回的变量本身的生命周期一定要大于函数,即不要返回局部变量的引用
5. 不要轻易返回堆空间变量的引用,除非已经有了对该堆空间内存回收的策略
- 只要返回的对象不受该函数的限制即可:Test& xxx_fun(...){return* this;}
- 不能将返回的栈变量作为其他引用的初始化,如:int& ref=fun(); // 错误
- 不能将返回的栈变量作为其他表达式的左传,如:fun()=x; // 错误