【C++入门第二期】引用 和 内联函数 的使用方法及注意事项
- 前言
- 引用的概念
- 初识引用
- 区分引用和取地址
- 引用与对象的关系
- 引用的特性
- 引用的使用场景
- 传值和引用性能比较
- 引用和指针的区别
- 内联函数
- 内联函数的概念
- 内联函数的特性
前言
本文主要学习的是引用 及 内联含函数,其中的引用在实际使用中会异常舒适。
引用的概念
概念:引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
打个比方:你的名字叫张小三,你妈叫你小张,同学叫你小三,公司员工叫你张总。如上所述虽然你名字叫张小三,但大家却叫着你不一样的别名(小张/小三/张总)且你也知道他们是在叫你。
初识引用
使用方法:
类型& 引用变量名(引用对象别名) = 引用对象;
如下变量 rival 引用了 ival
区分引用和取地址
注意:& 即可 取地址 也能 引用
区分方法:&左边 “为类型名”则为引用 ,&左边“不是类型名”则为取地址 (先记住后面会解释为什么)
引用与对象的关系
如下:rival 引用了对象vial ,打印出 rival 和 ivil 的值一致。
但仅仅只是值一样吗?
下面我打印出 rival 和 ivil 的地址,两者地址也一致。
经实践得出以下两个点:
1:引用和被引用对象存储的内容一致
2:引用和被引用对象的地址一致
总结:地址都一样所以他们访问的是同一块内存
再举个栗子:一开始我们给 00FEFA10( 开始的4字节)这块地址取名(变量名)为ival ,后面我们又给 00FEFA10( 开始的4字节)这块地址取个新名字 rval,且新老名字均可用。
提出问题:既然引用是给和被引用对象访问的是同一块内存,那其功能是否一致呢?
下图依然是 rival 引用了对象vial ,rival改变时 rvial 也改变 ,ival改变时 rvial 也改变。
这是肯定的因为两者地址都一样
引用的特性
-
引用在定义时必须初始化
引用等于是给某个变量取别名,所以必须明确(初始化)这个别名给谁 -
一个变量可以有多个引用
还是上面那个例子:你的名字叫张小三,你妈叫你小张,同学叫你小三,公司员工叫你张总。
虽然这几个名字有所不宜但都是你 -
引用一旦引用一个实体,再不能引用其他实体
可以看到当 pa 初始化为 a 的引用后,pa = b 时 b 只是把值赋值给了 pa
pa 和 a 的地址仍然一样,只是值发生了变化。由此可见 , 引用一旦初始化则引用对象就不会发生改变
4:当引用对象为const修饰对象时,引用也应为 const 修饰
当 a 为 const int 类型时,用 int 类型的 pa 引用 a 时会报错。原因是两者类型不匹配当int类型对象引用const int 对象时存在权力放大,这是不被编译器允许的,语法本身也不允许。
因为int 类型是变量 ,而 const int 是具有常量属性的。所以引用对象也应为 const int 类型 ;如下
4.1 但是如果被引用对象为 int 类型 ,引用可以为const int 类型
如上图被引用对象为 int 类型 ,引用可以为const int 类型,这种现象叫做权力缩小, 权力缩小是被编译器及语法所允许的。
就如下图,在C语言中当我们不想让指针通过解引用改变变量时,就会在类型前加const,这也是一种权力缩小
总结:
1. 引用在定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
4. 引用时权力只能同等(int 和 int )或 缩小,不能放大。但引用的权力缩小并不影响被引用对象
引用的使用场景
- 做参数
对比使用指针做参数使用起来更简单哦
- 做返回值
但是注意:返回的引用对象出了其函数作用域必须还存在,接收其返回值的对象将能接收到,如果返回对象出了函数作用域就被销毁了只能用传值返回
传值和引用性能比较
在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此大量用值作为参数或者返回值类型,效率是比较低的,尤其是当参数或者返回值类型非常大时,效率就更低。
如下是传值调用和传引用调用的测试代码
#include <time.h>
struct A { int a[100000]; };
void Test1(A a)
{}
void Test2(A& a)
{}
void DateTest()
{A a;size_t begin1 = clock();//计时用的for (size_t i = 0; i < 100000; ++i)//执行Test1函数次数Test1(a);// 以值作为函数参数size_t end1 = clock();size_t begin2 = clock();for (size_t i = 0; i < 100000; ++i)//执行Test2函数次数Test2(a);// 以引用作为函数参数size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "Test1(A)-time:" << end1 - begin1 << endl;cout << "Test2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{//test1();DateTest();return 0;
}
经测试当我们传的是 A 这样的结构体分别循环100000次时,传值调用和传引用调用相差巨大分别是759和2,两者相差300多倍
如下是传值和引用返回测试代码
#include <time.h>
struct A { int a[100000]; };
A a;//返回值
A Test1( )
{return a;
}
A& Test2( )
{return a;
}
void DateTest()
{size_t begin1 = clock();//计时用的for (size_t i = 0; i < 100000; ++i)//执行Test1函数次数Test1();// 以值作为函数参数size_t end1 = clock();size_t begin2 = clock();for (size_t i = 0; i < 100000; ++i)//执行Test2函数次数Test2();// 以引用作为函数参数size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "Test1(A)-time:" << end1 - begin1 << endl;cout << "Test2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{//test1();DateTest();return 0;
}
经测试当我们返回的是 A 这样类型的结构体分别循环100000次时,值返回和引用返回相差巨大分别是1549和2,两者相差700多倍
通过上述代码的比较,发现传值和引用在作为传参以及返回值类型上效率相差很大
我给定的测试数据量都比较大,方便让大家看出差距,具体可用上述代码自行测试哦;
引用和指针的区别
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间
在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。同时我们来看下引用和指针的汇编代码对比
如下图可以看到,引用和指针的汇编代码一致
引用和指针的不同点:
1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用在定义时必须初始化,指针没有要求
3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
4. 没有NULL引用,但有NULL指针
5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全
内联函数
引出:
当我们某个函数需频繁调用时,函数栈帧建立会异常频繁导致代码效率下降
以前我们会把一些短小的函数写成宏来解决这一问题比如下图
但是宏也有缺点:
1.不能调试
2.没有类型安全的检查
3.有些场景下非常复杂
而 C++ 针对这一问题设计出了内联函数 ,内联函数的关键字为 inline
inline int ADD(int x, int y)
{int ch = x + y;return ch;
}
int main()
{ADD(1,2);ADD(1, 2);return 0;
}
内联函数的概念
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。
查看设置
在 release 版本下,inline 内联函数会直接在调用部分展开但是 release 版本下其他版本优化的太多,不太好观察
debug 版本则需要自己设置一下编译器才能查看,否则不会展开因为debug不做代码优化
(vs2019)首先打开解决方案资源管理器,右击项目名称,选中属性并打开点击常规->调试信息格式,选择程序数据库
在 C/C++ 优化一栏,将内联函数扩展部分选中 ->只适用于 __inline (/Ob1)
设置完成点击应用
设置前汇编代码,可以看到需要调用ADD函数
设置后汇编代码可以看到,call ADD不见了,call 是函数调用的指令,没有说明代码没有进行函数调用,内联函数直接在局部展开了。
内联函数的特性
- inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
行效率。 - inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。下图为《C++prime》第五版关于inline的建议:
- inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
结论:函数内容较短,且频繁调用的函数建议定义成 inline 可节省函数栈帧的消耗
相关文章:

【C++入门第二期】引用 和 内联函数 的使用方法及注意事项
前言引用的概念初识引用区分引用和取地址引用与对象的关系引用的特性引用的使用场景传值和引用性能比较引用和指针的区别内联函数内联函数的概念内联函数的特性前言 本文主要学习的是引用 及 内联含函数,其中的引用在实际使用中会异常舒适。 引用的概念 概念&…...

数据结构——顺序表讲解
作者:几冬雪来 时间:2023年2月25日 内容:数据结构顺序表内容讲解 目录 前言: 顺序表: 1.线性表: 2.什么是顺序表: 3.顺序表的概念和构成: 4.顺序表的书写: 1…...

Redis 主从复制-服务器搭建【薪火相传/哨兵模式】
Redis 安装参考文章:Centos7 安装并启动 Redis-6.2.6 注意:本篇文章操作,不能在 静态IP地址 下操作,必须是 动态IP地址,否则最后主从服务器配置不成功! 管道符查看所有redis进程:ps -ef|grep re…...

数据库|(五)分组查询
(五)分组查询1. 介绍2. 语法3. 简单分组函数2. 添加筛选条件3. 添加复杂的筛选条件4. 分组查询特点5. 按表达式或函数分组6. 按多个字段分组7. 分组查询添加排序1. 介绍 引入:查询每个部门的平均工资 -- 以前写法:求的是总平均工…...

Orin安装ssh、vnc教程
文章目录一:ssh远程终端的配置PC的配置MobaXterm的下载二:VNC Viewer远程图形界面终端配置:PC配置:一:ssh远程 终端的配置 1.ifconfig查看终端ip地址 其中的eth是网口,我们需要看的是wlan0下的inet&#…...

Allegro如何快速删除孤立铜皮操作指导
Allegro如何快速删除孤立铜皮操作指导 在做PCB设计的时候,铺铜是常用的设计方式,在PCB设计完成之后,需要删除PCB上孤立的铜皮,即铜皮有网络但是却没有任何连接 如下图 通过Status报表也可以看到Isolated shapes 如何快速地删除孤立铜皮,具体操作如下 点击Shape...

从单管单色到单管RGB,这项MicroLED工艺不可忽视
微显示技术商Porotech,在CES 2023期间展示了最新的MicroLED显示模组。近期,AR/VR光学领域的知名博主Karl Guttag深度分析了该公司的微显示技术,并指出Porotech带来了他见过最有趣的MicroLED技术。Guttag表示:Porotech是本届CES上给…...

6-Java中新建一个文件、目录、路径
文章目录前言1-文件、目录、路径2-在当前路径下创建一个文件3-在当前路径下创建一个文件夹(目录)3.1 测试1-路径已经存在3.2 测试2-路径不存在3.2 创建不存在的路径并新建文件3.3 删除已存在的文件并新建4-总结前言 学习Java中如何新建文件、目录、路径…...

Bootstrap系列之Flex布局
文章目录Bootstrap中的Flexd-flex与d-inline-flex也存在响应式变化flex水平布局flex垂直布局flex水平与垂直也存在响应式变化内容排列(justify-content响应式变化也存在于这里sm,md,lg,xl)子元素对齐方式Align items&a…...

匈牙利算法与KM算法的区别
前记 在学习过程中,发现很多博客将匈牙利算法和KM算法混为一谈,当时只管用不管分析区别,所以现在来分析一下两个算法之间的区别。 匈牙利算法在二分图匹配的求解过程中共两个原则: 1.最大匹配数原则 2.先到先得原则 而KM算法求…...

You Only Need 90K Parameters to Adapt Light 论文阅读笔记
这是BMVC2022的论文,提出了一个轻量化的局部全局双支路的低光照图像质量增强网络,有监督。 思路是先用encoder f(⋅)f(\cdot)f(⋅)转到raw-RGB域,再用decoder gt(⋅)g_t(\cdot)gt(⋅)模拟ISP过程转到sRGB域。虽然文章好像没有明确指出&…...

【vue2小知识】实现axios的二次封装
🥳博 主:初映CY的前说(前端领域) 🌞个人信条:想要变成得到,中间还有做到! 🤘本文核心:在vue2中实现axios的二次封装 目录 一、平常axios的请求发送方式 二、axios的一次封装…...

走近php的数组:数组的定义与数组函数
数组是一种数据结构,它由一组元素组成,这些元素可以是相同类型或不同类型。数组是在程序运行时动态创建的,可以根据需要增加或删除元素,因此它们是非常灵活和实用的数据结构。在大多数编程语言中,数组都有一个索引&…...

Docker 应用实践-仓库篇
目前 Docker 官方维护了一个公共仓库 Docker Hub,用于查找和与团队共享容器镜像,界上最大的容器镜像存储库,拥有一系列内容源,包括容器社区开发人员、开放源代码项目和独立软件供应商(ISV)在容器中构建和分…...

python+django篮球NBA周边商城vue
目 录 第一章 绪 论 1 1.1背景及意义 1 1.2国内外研究概况 1 1.3 研究的内容 1 第二章 关键技术的研究 3 2.1 vue技术介绍 3 myproject/ <-- 高级别的文件夹 |-- myproject/ <-- Django项目文件夹 | |-- myproje…...

抽象类与接口的区别
抽象类什么是抽象类?抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象类可以包括抽象方法,这是普通类所不能的。抽象方法只能声明于抽象类中,且不包含任何实现&#…...

1904. 你完成的完整对局数
题目: 一款新的在线电子游戏在近期发布,在该电子游戏中,以 刻钟 为周期规划若干时长为 15 分钟 的游戏对局。这意味着,在 HH:00、HH:15、HH:30 和 HH:45 ,将会开始一个新的对局,其中 HH 用一个从 00 到 23…...

Vue3:自定义指令以及简单的后台管理权限封装
目录 前言: 自定义指令介绍: 局部的自定义指令: 全局自定义指令: 讲讲后台管理权限管理: 前言: 说起这个自定义指令的使用场景,我第一反应就是,后台管理的权限管理,要…...

剑指 Offer 12. 矩阵中的路径
摘要 剑指 Offer 12. 矩阵中的路径 一、回溯算法解析 本问题是典型的矩阵搜索问题,可使用 深度优先搜索(DFS) 剪枝解决。 深度优先搜索: 可以理解为暴力法遍历矩阵中所有字符串可能性。DFS 通过递归,先朝一个方向搜…...

springboot+jersey+tomcat实现跨域方式上传文件到服务器
前言 在服务器上,当我们启动了tomcat,就可以以 http://ip地址:8080/文件路径/文件名 的方式,进行访问到我们服务器上处于tomcat的webapps文件夹下的文件 于是为了可以往上面加文件,我们有两种方式,一种就是直接复制文…...

【微信小程序】-- 常用视图容器类组件介绍 -- view、scroll-view和swiper(六)
💌 所属专栏:【微信小程序开发教程】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &#…...

猜数字游戏——C++
我们在有了一定的C基础了以后,简单的实现一个案例(其实只要会while循环结构就行了),我们本章内容会实现猜数字游戏,大家有什么语法疑问可以看看我写的:C快速入门_染柒_GRQ的博客-CSDN博客,该博客…...

整数对最小和
题目描述 给定两个整数数组 array1 array2。数组元素按升序排列,假设从array1 、array2中分别取出一个元素可构成一对元素,现在需要取出K个元素并对取出的所有元素求和,计算和的最小值 注意事项 两对元素如果对应于array1 array2中的两个下…...

2023-2-22 -javaagent
周三,天气晴,7度 Java Agent Java Agent也叫作java探针,可以实现动态修改java字节码,完成额外的功能。在java类编译成字节码,在jvm执行之前,它可以读取修改字节码,以来完成额外的功能。 使用…...

JavaScript BOM操作
目录 前言 window 对象 location 对象 navigator 对象 screen 对象 history 对象 前言 BOM(Browser Object Model)指的是浏览器对象模型,它是 JavaScript 和浏览器之间的接口。通过 BOM,JavaScript 可以与浏览器窗口交互&…...

【机器学习 | 强基计划】开山篇 | 机器学习介绍及其类别和概念阐述
🤵♂️ 个人主页: @计算机魔术师 👨💻 作者简介:CSDN内容合伙人,全栈领域优质创作者。 机器学习 | 强基计划系列 (一) 作者: 计算机魔术师 版本: 1.0 ( 2022.2.25) 注释:文章会不定时更新补充 文章目录 前言一、机器学习概览1.1 有监督学习和无监督学习1.1.…...

华为OD机试真题Java实现【合规数组】真题+解题思路+代码(20222023)
合规数组 题目 给定一个正整数数组 检查数组中是否存在满足规则的数组组合 规则: A = B + 2C 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Java)真题目录汇总 ## 输入 第一行输出数组的元素个数 接下来一行输出所有数组元素,用空格隔开 输出 如果存在满…...

BoostSearcher搜索引擎项目
BoostSearcher搜索引擎项目 1.BoostSearcher这个项目是什么? 答:一个为Boost文档建立索引的站内搜索引擎,简单的说就是一个类似于csdn站内文档搜索框。 项目展示: gitee:https://gitee.com/zxlfx/boost-search-engine-project …...

【模拟集成电路】频率综合器(Frequency Synthesizer,FS)设计
应用于无线局域网的频率综合器设计前言频率综合器简介各部分链接链接:前言 本文主要内容是对频率综合器或称为PLL 做出简单介绍,为课程设计部分章节内容,后需给出各部分的设计方案,以及测试结果。 频率综合器简介 无线收发系统中…...

实例8:机器人的空间描述和变换仿真
实例8:机器人的空间描述和变换仿真 实验目的 通过刚体与刚体的平动、转动基础知识的学习,熟悉位姿的描述通过Python编程实践,可视化学习坐标系的变换,熟悉空间变换 实验要求 通过python编程,输入一指定向量和对应的…...