【C++】中的 inline 用法

1、引入 inline 关键字的原因

在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。

栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。

在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足而导致程序出错的问题,如,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

在代码中使用inline关键字可以将函数指定为内联函数。内联函数是一种在调用点将函数体直接插入而不是通过函数调用进行执行的优化方式。这可以减少函数调用的开销,提高程序的执行效率。

2、使用方法

  1. 在函数声明或定义前加上inline关键字。
inline int add(int a, int b) {return a + b;
}

  1. 调用内联函数时,编译器会将函数体插入调用点,而不是生成函数调用的代码。
int result = add(2, 3);  // 调用add函数,编译器会直接插入add函数的代码

需要注意的是,编译器可能会选择不将函数标记为内联函数。这通常发生在函数体较大或者递归调用的情况下。为了强制内联函数的行为,可以使用编译器特定的指令,例如在GCC中使用__attribute__((always_inline))

inline __attribute__((always_inline)) int add(int a, int b) {return a + b;
}

3、inline使用限制

inline 的使用是有所限制的,inline 只适合涵数体内代码简单的涵数使用,不能包含复杂的结构控制语句例如 while、switch,并且不能内联函数本身不能是直接递归函数(即,自己内部还调用自己的函数)。

4、inline仅是一个对编译器的建议

inline 函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思,它如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联,声明内联只是一个建议而已。

5、建议 inline 函数的定义放在头文件中

其次,因为内联函数要在调用点展开,所以编译器必须随处可见内联函数的定义,要不然就成了非内联函数的调用了。所以,这要求每个调用了内联函数的文件都出现了该内联函数的定义

因此,将内联函数的定义放在头文件里实现是合适的,省却你为每个文件实现一次的麻烦。

声明跟定义要一致:如果在每个文件里都实现一次该内联函数的话,那么,最好保证每个定义都是一样的,否则,将会引起未定义的行为。如果不是每个文件里的定义都一样,那么,编译器展开的是哪一个,那要看具体的编译器而定。所以,最好将内联函数定义放在头文件中。

6、类中的成员函数与inline

定义在类中的成员函数默认都是内联的,如果在类定义时就在类内给出函数定义,那当然最好。如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上 inline,否则就认为不是内联的。

7、inline 是一种"用于实现的关键字"

关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。

如下风格的函数 New 不能成为内联函数:

inline void New(int x, int y); // inline 仅与函数声明放在一起
void New(int x, int y){}

而如下风格的函数 New 则成为内联函数:

void New(int x, int y);
inline void New(int x, int y) {} // inline 与函数定义体放在一起

所以说,inline 是一种"用于实现的关键字",而不是一种"用于声明的关键字"。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但我认为inline不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。

8、慎用 inline

内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?如果所有的函数都是内联函数,还用得着"内联"这个关键字吗? 
内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。 
如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。

以下情况不宜使用内联: 
(1)代码比较长,使用内联将导致内存消耗代价较高。 
(2)如果函数体内出现循环或者递归,那么执行函数体内代码的时间要比函数调用的开销大。类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如"偷偷地"执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中

一个好的编译器将会根据函数的定义体,自动地取消不值得的内联

(这进一步说明了 inline 不应该出现在函数的声明中)

9、总结

内联函数并不能适用于所有情况。只有当函数非常短小的时候它才能得到我们想要的效果;但是,如果函数并不是很短而且在很多地方都被调用的话,那么将会使得可执行体的体积增大。 
最令人烦恼的还是当编译器拒绝内联的时候。在老的实现中,结果很不尽人意,虽然在新的实现中有很大的改善,但是仍然还是不那么完善的。一些编译器能够足够的聪明来指出哪些函数可以内联哪些不能,但是大多数编译器就不那么聪明了,因此这就需要我们的经验来判断。

如果内联函数不能增强性能,就避免使用它!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/681678.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot+Vue3 完成小红书项目

简介 该项目采用微服务架构,实现了前后端分离的系统设计。在前端,我们选择了 Vue3 配合 TypeScript 和 ElementUi 框架,以提升开发效率和用户体验。而在后端,则是运用 SpringBoot 和 Mybatis-plus 进行开发,保证了系统…

使用word2vec+tensorflow自然语言处理NLP

目录 介绍: 搭建上下文或预测目标词来学习词向量 建模1: 建模2: 预测: 介绍: Word2Vec是一种用于将文本转换为向量表示的技术。它是由谷歌团队于2013年提出的一种神经网络模型。Word2Vec可以将单词表示为高维空间…

JS逆向进阶篇【去哪儿旅行登录】【上篇】

目标url: aHR0cHM6Ly91c2VyLnF1bmFyLmNvbS9wYXNzcG9ydC9sb2dpbi5qc3A 实现难点: 逆向滑块请求发送短信登录 目录 每篇前言:0、前置技术栈(1)JS实现页面滑动(2)JS实现记录滑动轨迹(3&#xff…

SAP MM学习笔记42 - 特殊调达流程 - 受托品(寄售)

上一章讲了 外注加工的知识。 详细可以参考如下链接。 SAP MM学习笔记41 - 特殊调达流程 - 外注加工-CSDN博客 咱们继续学习特殊调达流程。 本章主要讲受托品。 1,什么是受托品 (寄售) 仕入先提供的商品,商品是放在你公司了&a…

一周学会Django5 Python Web开发-Django5 Hello World编写

锋哥原创的Python Web开发 Django5视频教程: 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计14条视频,包括:2024版 Django5 Python we…

java SSM新闻管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM新闻管理系统是一套完善的web设计系统(系统采用SSM框架进行设计开发,springspringMVCmybatis),对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S…

《Java 简易速速上手小册》第8章:Java 性能优化(2024 最新版)

文章目录 8.1 性能评估工具 - 你的性能探测仪8.1.1 基础知识8.1.2 重点案例:使用 VisualVM 监控应用性能8.1.3 拓展案例 1:使用 JProfiler 分析内存泄漏8.1.4 拓展案例 2:使用 Gatling 进行 Web 应用压力测试 8.2 JVM 调优 - 魔法引擎的调校8…

智能汽车行业产业研究报告:4D成像毫米波雷达—自动驾驶最佳辅助

今天分享的是智能汽车系列深度研究报告:《智能汽车行业产业研究报告:4D成像毫米波雷达—自动驾驶最佳辅助》。 (报告出品方:开源证券) 报告共计:43页 视觉感知最佳辅助——4D 成像毫米波雷达 感知是自动…

【Python】window环境使用venv部署jupyter notebook

基础信息 执行winr,在输入框输入powershell: python版本:python -v 创建并激活虚拟环境 1、进入要创建虚拟环境的目录,操作示例如下: PS C:\Users\Administrator> cd D:\Python\weltest 2、创建虚拟环境,操作示…

BUGKU-WEB GET

题目描述 没有提示,就一个get,启动场景看看: 解题思路 显然是PHP语言解读分析代码吧写出你的payload 相关工具 略 解题步骤 进入场景分析代码 $what$_GET[what]; echo $what; if($whatflag) echo flag{****};前两句:使用get…

2024年最新指南:如何订阅Midjourney(详尽步骤解析)

前言: Midjourney是一个基于人工智能的图像生成工具,它使用高级算法来创建独特和复杂的图像。这个工具能够根据用户输入的文字描述生成对应的图片。Midjourney的特点在于它能够处理非常抽象或者具体的描述,生成高质量、富有创意的视觉内容。M…

Flaurm实现中文搜索

目录 摘要需求本文涉及环境情况如下解决方案最终效果文章其他链接: 摘要 Flarum本身对中文支持并不理想,但随着版本更新,逐渐加强了对中文的优化。然而在1.8.5版本,却还是不支持中文搜索网站文章内容。作者在检索了全网教程&#…

数模.SI模型SI的四种扩展

一:最简单的考虑方式 二考虑某种使得参数beta降低的因素 三:增加人口自然出生率和死亡率,但不考虑疾病的死亡率 四:不考虑人口自然出生率和死亡率,只考虑疾病的死亡率 五:同时考虑人口自然出生率和死亡率和…

kali系统概述、nmap扫描应用、john破解密码、抓包概述、以太网帧结构、抓包应用、wireshark应用、nginx安全加固、Linux系统加固

目录 kali nmap扫描 使用john破解密码 抓包 封装与解封装 网络层数据包结构 TCP头部结构​编辑 UDP头部结构 实施抓包 安全加固 nginx安全 防止缓冲区溢出 Linux加固 kali 实际上它就是一个预安装了很多安全工具的Debian Linux [rootmyhost ~]# kali resetkali …

C#一维数组排序方法:选择排序法

目录 一、数组元素常见的排序法 1.选择排序法 二、实例1:选择排序法 1.源码 2.生成效果 一、数组元素常见的排序法 常见的排序法:选择排序法、冒泡排序法、快速排序法、直接插入法、希尔排序法、Array.Sort方法。 1.选择排序法 通过遍历实现排序&…

基于Qt的人脸识别项目(功能:颜值检测,口罩检测,表情检测,性别检测,年龄预测等)

完整代码链接在文章末尾 效果展示 代码讲解(待更新) qt图片文件上传 #include <QtWidgets> #include <QFileDialog>

多模态学习综述(MultiModal Learning)

最早开始关注到多模态机器学习是看到Jeff Dean在2019年年底NeurIPS大会上的一个采访报道&#xff0c;讲到了2020年机器学习趋势&#xff1a;多任务和多模态学习将成为突破口。 Jeff Dean 谈2020年机器学习趋势&#xff1a;多任务和多模式学习将成为突破口 站在2022年&#xff…

如何流畅进入Github

前言 以下软件是免费的&#xff0c;放心用 一、进入右边的下载链接https://steampp.net/ 二、点击下载 三、点击接受并下载 四、随便选一个下载链接进行下载 五、软件安装好打开后&#xff0c;找到Github 六、点击全部启用 七、再点击左上角的一键加速 八、这个时候你再进Git…

LAXCUS分布式操作系统目标:软件算力入口

英伟达现在的市值相当于整个中国股市&#xff01;说明了什么&#xff1f; AI 大潮下&#xff0c;算力就是生产力&#xff0c;也是未来 20 年一切产业的基础&#xff0c;英伟达已经把住硬件算力入口&#xff0c;LAXCUS 分布式操作系统瞄准软件算力入口&#xff0c;做好了&#…

Linux第53步_移植ST公司的linux内核第5步_系统镜像打包并烧录到EMMC

本节主要学习系统镜像打包&#xff0c;然后将打包文件烧录到EMMC测试。 1、创建bootfs文件夹 1)、打开第1个终端 输入“ls回车” 输入“cd linux/回车”&#xff0c;切换到“linux”目录 输入“ls回车”&#xff0c;列出“linux”目录下的文件和文件夹 输入“cd atk-mp1/…