前言:
在计算机编程中,引用和指针是两个重要的概念,它们用于处理内存中的数据。它们在很多编程语言中都有相应的支持,例如C++和C。对于c语言来说,指针是最重要的概念之一,想要学好c语言就难以绕开对于指针的学习。那么对于c++来说,引用这一概念也同样如此。如果对指针还有不太了解的同学可以去看看我的关于指针初阶到进阶的博客,内容非常详细:
C语言内功修炼---指针详讲(初阶)-CSDN博客
C语言内功修炼--指针详讲(进阶)-CSDN博客
1.引用概念
引用是一个别名,它为一个已存在的变量提供了一个额外的名字。引用在声明时必须初始化,并且在其生命周期内始终引用相同的变量。可以理解为给某个变量起一个外号。
引用的声明
类型& 引用变量名(对象名) = 引用实体
int num = 42;
int &ref = num;//注意,引用必须初始化,且不能修改其引用对象
ref = 55; // 修改ref会影响num
引用类型必须和引用实体是同种类型的
2.引用的特性
1. 引用在定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
3.常引用
C++ 中的 "常引用"(const reference)是指在声明引用时使用了
const
修饰符,从而表明引用所指向的值不能被修改。常引用的主要作用是在函数参数传递中,以及在函数返回值中避免不必要的拷贝。
观察以下代码:
当我们想引用一个常量时,需要加const 修饰,因为本身常量就不能被修改。这里涉及到权限大小的概念,一般认为,相同的变量用const修饰会使得该变量的权限”变小了“。而我们的编译器认为权限变小或者权限相等是安全的,权限变大是不安全的。这也是为什么我们想引用一个常量需要用const修饰。
为什么使用常引用?
1.避免拷贝: 在函数参数传递中,使用常引用可以避免不必要的对象拷贝,提高程序性能。如果不使用常引用,传递大型对象时可能会导致额外的拷贝操作。
2.保护数据: 常引用可以用于声明对数据的只读访问,防止在函数内部意外修改传递的数据。
3.适用于临时对象: 常引用可以绑定到临时对象,使得在函数调用期间可以使用这些临时对象,而不需要为其创建命名变量。
4.引用的使用场景
1.做参数
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
比如我们想 实现一个交换数值函数,使用引用就可以通过改变形参的值来影响实际参数,类似指针。
2.做返回值
我们可以看到,因为n被static修饰,在静态区,生命周期是全局,所以当我们返回其引用时依旧可以访问并修改n的值。a作为返回值其实也是一个对n的引用,而对a修改实际上就是对n修改。
那如果n没有被static修饰,却被作为引用返回了呢?
思考以下代码
函数返回时,出了函数作用域,如果返回对象还在(还没还给系统,比如被static修饰或者是全局变量),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。像上述代码的变量c,出了函数作用域后该变量的空间就被系统回收了,此时ret的地址同样是被回收的变量c之前的地址,再输出ret就会出现不确定的结果。因为我们已经不知道该空间被回收之后干了什么(可能被其它变函数栈帧中的变量覆盖),所以得到的结果是不确定的。
5. 传值、传引用效率比较
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。那么对于引用来说,它不需要临时拷贝,而是返回一个"别名",用做形参时,也只是一个临时的”别名“,函数生命周期结束,该别名就直接被销毁。这一点来说,引用和指针起到的作用几乎是一样的。
1.传参效率比较
测试方法:两个被测试函数只允许参数类型不一样,函数调用相同次数的情况下,分析各自所需时间大小。
2.返回值效率比较
测试方法:两个被测试函数只允许返回值类型不一样,函数调用相同次数的情况下,分析各自所需时间大小。
总结:
无论是做参数还是做返回值,传值和指针在作为传参以及返回值类型上效率相差很大。
6.引用和指针的区别
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
但是 在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
引用和指针的不同点:
1. 引用概念上是定义一个变量的别名,指针存储一个变量地址。
2. 引用在定义时必须初始化,指针没有要求
3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体。
4. 没有NULL引用,但有NULL指针。
5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全引用在定义时就与变量绑定了,指针可以随意切换指向的地址空间。从某种角度来说,权限越大,越不安全。