引用
引用
引用的使用与概念
在使用引用的过程中,要注意以下几点:
1.&不再是取地址符号,而是引用符号
2.引用的类型需要和其绑定的变量的类型相同
3.声明引用的同时,必须对引用进行初始化,否则编译时报错
4.引用一经绑定,无法更改绑定
1
2
3
4
5
6
7
8
9
10
11
12 //引用其实就是起别名
int num = 100;
//和int *p = &num 有点类似
int &ref = num;
ref += 1;
cout << num << endl;
//对于引用取址,返回的一定是其绑定的变量本体的地址
cout << &ref <<endl;
int & ref2;//error 必须初始化
ref = num2;//这里本质上是一个赋值操作,不是更改绑定 本质上是num = num2;
引用的本质
引用的本质上是一种被限制的指针,类似于线性表和栈的关系,由于引用是被限制的指针,所以引用是会占据内存的,占据的大小就是一个指针的大小,但是编译器阻止了对他本身的任何访问,从一而终的总是指向初始的目标单元,引用的本质是“间接取值”
引用和指针的联系和区别
这是一道非常经典的面试题,请尝试着回答一下:
联系:
引用和指针都有地址的概念,都是用来间接访问变量;
引用的底层还是指针来完成,可以把引用视为一个受限制的指针。(const pointer)
区别:
- 引用必须初始化,指针可以不初始化;
- 引用不能修改绑定,但是指针可以修改指向;
- 在代码层面对引用本身取址取到的是变量的地址,但是对指针取址取到的是指针变量本身的地址
引用的使用场景
1.引用作为函数的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 //不会发生复制,相当于是指向,在函数体中对引用进行操作就是对实参本身进行操作
void swap(int &x, int &y){
int temp = x;
x = y;
y = temp;
}
int main(){
int a = 1;
int b = 2;
swap(a, b);
cout << "a = " << a << ", b = " << b << endl;
}
//如果不希望函数体通过引用改变传入的变量,那么可以使用常引用函数参数
//如果ref所指向的对象占的内存很大,那么使用这种方法可以节约内存的开销
void func(const int &ref){
ref = 100;//error 不可以修改
}
2.应用作为函数的返回值
当普通函数返回值时是会发生复制的,而使用引用不会发生复制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 int func1(){
int num = 100;
return num;//func1的返回值是一个临时的变量而且是一个匿名的变量,不可以取址
}
void test(){
cout << func1() <<endl;
&func1();//error 是临时变量,不可以取址,他的生命周期只在当前行
}
"------------------------------------"
int num = 100;
int func1(){
return num;
}
void test(){
&func1();//error 即使返回值是全局变量的副本,那就是匿名变量,生命周期只在当前行,不能进行取址
}
//-----------------------------------------
int num = 100;
int &func2(){
return num;//执行return语句时,不会发生复制,而是定义了一个绑定到num的引用(没有名字的引用)
}
void test(){
&func2();//可以取地址。
func2 = 1000;//甚至可以修改
cout << num << endl;//1000
}注意事项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 int & func(){
int num = 10;
return num;//error 不要返回局部变量的引用,函数返回类型为引用时,要确保其绑定的本地生命周期比函数更长,类比指针函数
}
int & func2(){
int *p = new int();
cout << p << endl;
return *p;
}
void test(){
cout << &func2() <<endl;//两个打印结果一样
cout << func2() <<endl;
func2() = 300;
cout << func2() << endl;//打印值都是30
//内存泄漏了12bit,调用一次func2就new了一个新的堆空间,但是函数在调用完已经被销毁了,但是却没法回收这部分空间了,会造成内存泄漏
//要释放这部分空间,要哪一个临时的指针指向这部分空间
int ref = func2();
delete ref;
}
总结
引用总结:
- 在引用的使用中,单纯给某个变量取个别名没有什么意义,引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不理想的问题。
- 用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,还可以通过const的使用,保证了引用传递的安全性。
- 引用与指针的区别是,指针通过某个指针变量指向一个变量后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;引用底层仍然是指针,但是编译器不允许访问到这个底层的指针,逻辑上简单理解为——对引用的操作就是对目标变量的操作。可以用指针或引用解决的问题,更推荐使用引用。
本文是原创文章,采用CC BY-NC-SA 4.0协议,完整转载请注明来自The Yue