引用的概念
什么是引用呢,简单的来说就是给变量起一个其他的名字,然后这个其他的名字和变量的地址是一样的,编译器并不会新开辟一块空间。比如给某人起一个绰号,其实这个绰号还是一个人。 例如下面就是一段简单的引用 ``
#include<iostream>
using namespace std;
int main()
{
int a = 0;
double d = 1.5;
int& i = a;
double& e = d;
cout << a << endl;
cout << i << endl;
cout << d << endl;
cout << e << endl;
}
输出结果
引用的作用在哪里
把引用作为参数
作用提升了效率,而且安全,还可以修改返回变量 举个例子
void Swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
我们常常写交换函数,用指针进行交换,对于这个函数在调用的时候会开辟栈帧,把临时变量存进去,从而消耗了空间。我们可以使用引用
void Swap(int& a, int& b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
这样的话避免新建指针变量,效率变得就比较高了。而且引用就是一个别名,所以变量可以很容易的被修改。
把引用作为返回值
我们先看这样一个简单的示例
int add(int a, int b)
{
int c = a + b;
return c;
}
一般来说这个函数可以完成正常的加法功能,但是存在一个问题,返回值并不是c,而是c的一个拷贝,这个函数在调用之后就会被销毁,变量也被销毁了。但是为什么能返回的,原因是因为这个c拷贝到了内存中,可以是寄存器里边,再由寄存器返回给调用者。如图
我们可以用引用作为返回值
int& add(int a, int b)
{
int c = a + b;
return c;
}
//引用返回就是直接返回c的值,也就是c的别名,而不是c的拷贝,这样就节约了空间
int main()
{
int& res = add(1, 2);
cout << res << endl;
}
看下边的一个问题
int& add(int a, int b)
{
int c = a + b;
return c;
}
//引用返回就是直接返回c的别名,创建一个函数栈帧,把c的别名保存起来
int main()
{
int& res = add(1, 2);
add(10, 20);
cout << res << endl;
}
为什么是三十呢,这是因为函数再次调用的时候,函数栈帧被覆盖了
int& add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int res = add(1, 2);
cout << res << endl;
}
这段代码存在问题,第一个是非法访问,因为add返回的是c的引用,当函数调用完毕后,c被销毁了,所以就非法访问了,第二个是如果清理空间,那么就会访问到随机值了,这就取决于编译器如何实现的了,我们再来看看下边的
这里的打印函数把c对应的栈帧给覆盖了,所以产生了随机值。所以使用引用作为返回值还是要慎重的。
这里要注意的是,如果返回引用的话,出了函数作用域,变量还没有返还给系统,那么就可以用,否则就不能用。
总结:
- 引用作为返回值和传参数的时候,对于一些场景(传大对象深拷贝的时候)是可以提高性能的
- 另外可以用于形式参数的改变可以改变实参
常引用
int main()
{
//const int a = 10;
//int& b = a;
const int c = 10;
const int& d = c;
int e = 10;
const int& f = e;
}
第一段const int 表示这个变量是只读的,后边变成了int 这叫权限的放大,而第三段这个e又能读又能写,下边变成了const int,这个叫权限的缩小,就可以编译的过去
常引用的应用
void ppp(int& x)
{
cout << x << endl;
}
int main()
{
//const int a = 10;
//int& b = a;
const int c = 10;
const int& d = c;
int e = 10;
const int& f = e;
ppp(f);
}
这里会出现错误原因是你传入了一个const int 的值给了int& ,权限被放大了,正确的方法应该是下面的
void ppp(const int& x)
{
cout << x << endl;
}
int main()
{
//const int a = 10;
//int& b = a;
const int c = 10;
const int& d = c;
int e = 10;
const int& f = e;
ppp(f);
}
**总结一下就是,如果你的函数的参数不改变,参数是一个大对象或者是深拷贝,你还想传入引用,那么你就最好用 const type 作为参数类型。 **
注意的几个地方
- 引用的时候必须要有初始值
- 一个变量可以有多个引用
- 引用一旦引用了一个变量,就不能引用第二个了
引用和指针的区别
- 引用是一个别名,而指针是一个实体
- 访问目标时,指针要解引用,而引用直接用
- 指针可以有多级,而引用就一级
- 指针可以指向空,而引用却不可以
- sizeof的运算符是不同的,对于指针是四个字节,而引用要根据引用多大的变量了
- 对于引用的自增就是加一,而指针就是指向下一段地址了