C++引用上

简介: 用不是新定义一个变量,而是给已存在的变量取一个别名,译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

引用

引用不是新定义一个变量,而是给已存在的变量取一个别名,译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。


在语法上,一定要认为引用没有开空间,目前先不用考虑底层上


引用的语法为:类型& 引用变量名(对象名) = 引用实体;


引用类型必须和引用实体是同种类型的


int main()
{
  int a = 10;
  int& b = a;//定义引用类型
}


b是a的引用,a和b本质上是一个变量,它们公用一个空间,改变任意一个另一个都会改变



afb3f9e8676746f7980536772d92748d.png



引用时必须进行初始化

int main()
{
  int a = 10;
  int& b;//引用时需要初始化,这样写是错误的
}


一个变量可以有多个引用

int main()
{
  int a = 10;
  int& b = a;
  int& c = b;
}


b是a的·引用,c又是b的引用,所以b和c都是a的引用,它们三个共用一个空间



47c4cedbe1de4637bded9722eabd1dec.png



引用一旦引用了一个实体,不能再引用另一个实体

int main()
{
  int a = 10;
  int x = 5;
  int& b = a;//b已经是a的引用了
  b = x;//这里不会改变b引用的实体,只是把x的值拷贝给了b,b还是a的引用
}


引用的使用

引用做参数

1.引用做参数,常用于输出型参数


输出型参数就是在函数内部改变,并且在函数外部还能拿到的参数,其实也可以成为“形参的改变可以影响实参”

例如交换两个变量值,这2个变量在后序程序中还会用到,所以是输出型变量,在一些关于数组的OJ题中,一般函数参数都有一个表示数组大小的变量numSize,这个形参也是输出型参数


下面通过引用实现一个swap函数


void swap(int& x, int& y)
{
  int tmp = x;
  x = y;
  y = tmp;
}


再对比一下原先在C语言中的写的swap:


void swap(int* x, int* y)
{
  int tmp = *x;
  *x = *y;
  *y = tmp;
}


可以看到用引用最直接的一个点就是不需要再传指针了

以往的swap函数中,为了在函数中能够改变要交换的2个数的值,只能传指针,否则就是形参的改变不会影响实参

在C++中,传引用,形参就是实参的别名,这样形参的改变就可以改变实参


2.引用做参数,可以提高效率,尤其是对于深拷贝的类对象和大对象


以值作为函数传参,在传参过程中,函数不会直接传递实参,而是传递实参的一份临时拷贝,以这个临时拷贝作为函数的形参,在值传递的过程中有拷贝操作,效率低下

在这个过程中,如果实参是深拷贝的类对象或者是大对象,那么它们的拷贝就会大大降低效率


所以,可以用引用做参数,在传参的过程中,没有拷贝的操作,形参就是实参的一个别名,这样能大大地提高效率


需要注意的一点:引用传参和指针传参效率一样,不存在较大的效率差异


下面我们看一下值传参和引用传参的效率差异:


struct A
{
  int a[10000];
};
void func1(A a){}//值传参
void func2(A&a){}//引用传参
int main()
{
  A a;//大对象
  int BeginTime1 = clock();
  for (size_t i = 0; i < 10000; ++i)
  func1(a);
  int EndTime1 = clock();
  int BeginTime2 = clock();
  for (size_t i = 0; i < 10000; ++i)
  func2(a);
  int EndTime2 = clock();
  cout << "值传参:" << EndTime1 - BeginTime1 << endl;
  cout << "引用传参:" << EndTime2 - BeginTime2 << endl;
}



可以看到,引用传参消耗的时间明显少于值传参

2e6b63620a17476eb805972522d6b6bf.png


引用做返回值

在学习引用做返回值之前,要了解一下返回return的作用机制:

在函数中,return了一个值或变量后,并不会直接返回,在中间会生成临时变量,最后返回的值其实是临时变量



3565f6adae6b44548018784e80f19814.png


在这个过程中,会有拷贝操作,拷贝会导致效率低


为什么要设置临时变量? 如果返回值的作用域是这个函数,函数栈帧销毁后,返回值也被销毁了


所以为了解决这个问题,我们可以引用做返回值:


int& func()
{
  static int n = 0;
  n++;
  return n;
}
int main()
{
  int ret = func();
  return 0;
}


传引用返回,中间就不会生成临时变量了,可以减少拷贝,提高效率


从下图就可以看出,用引用返回可以减少一次拷贝




9c094131861042659142f13e0da80695.png


下面是用一个引用去接受引用返回:


int& func()
{
  static int n = 0;
  n++;
  return n;
}
int main()
{
  int& ret = func();
  return 0;
}


这里我们用一个引用接收了引用返回,ret其实就是n的别名


这样可以再减少一次拷贝,还能提高效率


99d3d22fb686491e9049f12aff48268a.png





这里需要注意的是,想要使用引用返回,那么要返回的值不应该随着函数栈帧的销毁而销毁,换而言之,返回的变量应该是储存在静态区或者是动态开辟出来的,从上面的代码可以看出,里面返回的n都是用static修饰过的,如果是局部对象的话,会有问题


目录
相关文章
|
5月前
|
存储 安全 C++
C++中的引用和指针:区别与应用
引用和指针在C++中都有其独特的优势和应用场景。引用更适合简洁、安全的代码,而指针提供了更大的灵活性和动态内存管理的能力。在实际编程中,根据需求选择适当的类型,能够编写出高效、可维护的代码。理解并正确使用这两种类型,是掌握C++编程的关键一步。
76 1
|
6月前
|
C++
C++中的const指针与const引用
C++中的const指针与const引用
79 2
|
4月前
|
存储 安全 C++
浅析C++的指针与引用
虽然指针和引用在C++中都用于间接数据访问,但它们各自拥有独特的特性和应用场景。选择使用指针还是引用,主要取决于程序的具体需求,如是否需要动态内存管理,是否希望变量可以重新指向其他对象等。理解这二者的区别,将有助于开发高效、安全的C++程序。
32 3
|
4月前
|
存储 自然语言处理 编译器
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
|
5月前
|
存储 安全 编译器
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
66 5
|
5月前
|
C++
C++引用
C++引用
|
5月前
|
存储 安全 编译器
【C++入门】—— C++入门 (中)_引用
【C++入门】—— C++入门 (中)_引用
37 5
|
5月前
|
C语言 C++ 编译器
【C++语言】冲突-C语言:输入输出、缺省参数、引用、内联函数
【C++语言】冲突-C语言:输入输出、缺省参数、引用、内联函数
【C++语言】冲突-C语言:输入输出、缺省参数、引用、内联函数
|
5月前
|
安全 测试技术 C++
C++中的引用
C++中的引用
29 1