一、概念
引用(类型& 变量),只是给一个已有的变量起了一个别名,在语法层次上讲,并不开辟新的空间
二、引用传参
下面用常见的Swap函数距离,下面的三个函数只有传参方式不同,分别是传值传参,传址传参和传引用传参
看一下结果,发现传值传参并不可以改变实参的值,而传址和传引用就可以成功交换x和y的值
不同 : 传址会为指针开辟新的空间,传引用只是取了一个别名,并没有开辟空间
相同 : 都可以在函数内部改变实参的值
可是如果在特定场景下,程序要求不改变实参的值,只是访问,那么用什么方法好呢?
其实如果要求不改变实参的值,很多人就想到那就用传值调用吧,但是如果你的变量不是一个单纯的int x,而是如下的一个结构体呢?
typedef struct Big
{
int a[1000000];
char b[1000000];
//...很庞大的数据
}Big;
如果在这里选择传值调用,那么系统必须再开辟一个很庞大的结构体,很浪费系统时间空间资源
如果遇到了数据量很庞大,又不希望在函数内部改变实参的值得时候,我们可以选择用常引用传参
这样既节省了空间,又不担心数据在函数调用时改变
三、常引用
当你相对一个常数进行引用的时候,编译器会报错,那么怎样改正呢
其实把他改成常量引用就可以了,因为20自身应该属于一个 const int 类型的常量
在观察下面这种情况
当常量和别名类型不相同时,编译无法成功
代码改正为
四、引用做返回值
先看一个传值返回
和之前的例子一样,返回值的别名的权限不可放大,所以只要在把ret改为 const int型即可
下来再看一个传引用返回的例子
调试代码,我们发现一个很奇怪的现象
我们调用第二次Add函数的时候,并没有给ret赋值,但是ret的值却改变了
也就是说,ret 是 c的一个别名,如果我们在两次调用Add函数之间进行了其他的操作,那么 c 这块空间就可能是其他操作进行过程中形成栈桢,给这块空间赋予了一个随机值
传值和传引用返回的差别
传值返回会形成一个中间的临时变量,而临时变量具有常性,需用const类型接收
传引用返回,不会产生常量,他只是返回值那块空间的别名,但是,上例中的 c是Add函数的变量,他的生命周期只在Add函数的花括号里,一旦栈桢结束,空间就会被释放掉,这时候任意的函数都可以占用这块空间,所以 c 这块空间的值就是个不确定的值,而 ret 又是c的别名,所以 ret 也随时可能被修改,这并不是我们想要的结果,怎样才可以让 ret 的值不会改变?
其实,如果 ret 所指代的空间( c )是一个在Add程序结束以后不会释放掉的空间,那么这块空间的就不能随意的被其他函数占用,也就是说,ret所指代的空间( c ),他的生命周期大于Add的生命周期就可以了
总结: 尽量不要返回一个临时变量的引用
如果出了作用于他还存在,就尽量使用引用(提高效率 :如果返回的是一个很大的空间,就不用再做一份临时拷贝)
那么什么时候出了作用于他还存在呢?典型的就是 静态的,或者 全局的,或者是传参传进去的
五、汇编层看引用的特性
六、引用和指针的异同
1. 引用"从一而终",只能定义时初始化一次
指针变量的值可以改变
2. 引用必须初始化
指针可以不初始化
3.当使用sizeof时的意义不同
引用:sizeof是当前类型的字节大小
指针:sizeof是指针的字节大小
4. ++,--操作符意义不同
引用使用 ++,--操作符时加减的都是一个常量1
指针使用 ++,--操作符时加减的是指针所指类型字节的大小
5. 引用相对来说安全一些
指针可能会形成野指针,造成内存泄漏