当前位置: 首页 > news >正文

C++引用详解

顾得泉:个人主页

个人专栏:《Linux操作系统》  《C/C++》  《LeedCode刷题》

键盘敲烂,年薪百万!


一、引用的概念

       引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
       比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"。

       类型& 引用变量名(对象名) = 引用实体

简单举个例子:

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


二、引用的特性

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体
void TestRef()
{int a = 10;// int& ra;   // 该条语句编译时会出错int& ra = a;int& rra = a;printf("%p %p %p\n", &a, &ra, &rra);  
}

结果如下:


三、常引用

void TestConstRef()
{const int a = 10;//int& ra = a;   // 该语句编译时会出错,a为常量const int& ra = a;// int& b = 10; // 该语句编译时会出错,b为常量const int& b = 10;double d = 12.34;//int& rd = d; // 该语句编译时会出错,类型不同const int& rd = d;
}

结果如下:


四、使用场景

1.做参数

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}

2.做返回值

int& Count()
{static int n = 0;n++;// ...return n;
}

思考:下面代码输出什么结果?为什么?

int& Add(int a, int b)
{int c = a + b;return c;
}
int main()
{int& ret = Add(1, 2);Add(3, 4);cout << "Add(1, 2) is :"<< ret <<endl;return 0;
}

注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回

3.效率比较

       以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();
// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

结果展示:

4.性能比较

#include <time.h>
struct A{ int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a;}
// 引用返回
A& TestFunc2(){ return a;}
void TestReturnByRefOrValue()
{// 以值作为函数的返回值类型size_t begin1 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc1();size_t end1 = clock();// 以引用作为函数的返回值类型size_t begin2 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc2();size_t end2 = clock();// 计算两个函数运算完成之后的时间cout << "TestFunc1 time:" << end1 - begin1 << endl;cout << "TestFunc2 time:" << end2 - begin2 << endl;
}

结果展示:

       通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大。


五、引用和指针的区别

       在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

int main()
{int a = 10;int& ra = a;cout<<"&a = "<<&a<<endl;cout<<"&ra = "<<&ra<<endl;return 0;
}

 结果如下:

       在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

int main()
{int a = 10;int& ra = a;ra = 20;int* pa = &a;*pa = 20;return 0;
}

       我们来看下引用和指针的汇编代码对比:

总结:

       1.引用概念上定义一个变量的别名,指针存储一个变量地址。
       2.引用在定义时必须初始化,指针没有要求
       3.引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
       4.没有NULL引用,但有NULL指针
       5.在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
       6.引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
       7.有多级指针,但是没有多级引用
       8.访问实体方式不同,指针需要显式解引用,引用编译器自己处理
       9.引用比指针使用起来相对更安全


结语:关于引用的简单分享到这里就结束了,希望本篇文章的分享会对大家的学习带来些许帮助,如果大家有什么问题,欢迎大家在评论区留言,最后祝大家新的一年里学业有成,天天开心~~~ 

相关文章:

  • 在WebSocket中使用Redis出现空指针异常解决方案
  • Linux——如何使用sftp命令轻松上传和下载文件
  • HTTPS实现原理
  • 软件工程知识梳理2-需求分析
  • 离线使用Element UI和Vue
  • Spring Cloud Gateway
  • linux☞ Centos 基础篇
  • 【C++】构造函数和析构函数详解
  • python查询xml类别
  • 在JAVA中如何使用ASCLL码
  • go语言文件操作
  • 回归预测 | Matlab实现CPO-LSSVM冠豪猪算法优化最小二乘支持向量机多变量回归预测
  • JVM 执行引擎
  • Linux实验记录:使用iptables
  • 《Docker极简教程》--前言--Docker的简介
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • ES2017异步函数现已正式可用
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • MySQL几个简单SQL的优化
  • PHP的类修饰符与访问修饰符
  • Puppeteer:浏览器控制器
  • Python爬虫--- 1.3 BS4库的解析器
  • socket.io+express实现聊天室的思考(三)
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 番外篇1:在Windows环境下安装JDK
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 模型微调
  • 微信小程序开发问题汇总
  • 问题之ssh中Host key verification failed的解决
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • Python 之网络式编程
  • 阿里云ACE认证之理解CDN技术
  • 阿里云服务器购买完整流程
  • (3)llvm ir转换过程
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (三)模仿学习-Action数据的模仿
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (转)Sql Server 保留几位小数的两种做法
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .NET 4.0中的泛型协变和反变
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .net 按比例显示图片的缩略图
  • .NET 使用 XPath 来读写 XML 文件
  • .Net6 Api Swagger配置
  • .net6使用Sejil可视化日志
  • .net解析传过来的xml_DOM4J解析XML文件
  • .NET委托:一个关于C#的睡前故事
  • @DateTimeFormat 和 @JsonFormat 注解详解
  • @synthesize和@dynamic分别有什么作用?
  • [ Algorithm ] N次方算法 N Square 动态规划解决