C++语法_深度剖析C++中的inline函数
目录
1.inline函数的爱恨两难
2.inline函数卑微在线求助
3.inline函数与虚函数的爱恨纠缠
4.糟糕的内联选择:构造函数与析构函数
5.总结
1.inline函数的爱恨两难
内联函数比宏优点好很多,详细原因请参见尽量以const、enum、inline替换#define 。调用内联函数不需要承受函数调用所导致的额外内存开销,编译器最优化机制通常被设计用来浓缩那些“不含函数调用”的代码,所以当一个函数为内联函数时,或许编译器就因此有内联对其执行语境相关的最优化。
“世界上没有免费的午餐”,内联函数背后的整体思想是:对一个函数的调用都以函数本体替换它,但这同时会增加你的目标码大小。在一个内存有限的机器上,过度使用内联函数会造成程序体积太大。即使用有虚拟内存,内联函数造成的代码膨胀也会导致额外的换页行为,降低指令高速缓存器的命中率。
另一方面来说,如果内联函数的本体很小,编译器针对函数本体所产生的码可能比函数调用所产生的码更小。因此,将函数设置为inline,确实导致更小的目标码和较高的命中率。
2.inline函数卑微在线求助
inline只是对编译器的一个申请建议,不是强制命令,编译器可以选择对你的建议置之不理。这项申请可以隐式声明也可以显式声明,隐式声明是将函数定义在类的内部,如下所示:
class Person{
public:// ...int age() const {return mAge;} // 隐式的内联函数
private:int mAge;
};
显式声明的方法则是在函数定义式前面加上关键字inline,如下面函数模板:
template<typename T>
inline const T& max(const T& a, const T& b){return a < b ? b : a;
}
上述显式的声明方法中,值得注意的一点是:inline函数和函数模板通常都被定义于头文件中。但是,函数模板未必一定是内联的!!!inline函数通常一定被放置在头文件中,因为大多数构建环境在编译过程中进行内联动作,为了将一个函数调用替换为被调用函数的本体,编译器必须知道那个函数是啥样。内联动作在大多数C++程序中是编译期的行为。函数模板通常也被放置在头文件中,因为它一旦被使用,编译器为了将它具体化,需要知道它的样子。某些构建环境中,可以在连接期执行模板具体化,只不过编译期完成具体化的动作比较常见。
3.inline函数与虚函数的爱恨纠缠
大部分编译器拒绝将太复杂(带有循环或递归、switch-case语句)的函数设置为inline,而且所有对虚函数的调用也都会使inline失效。这是因为虚函数是直到运行期才会确定调用哪个函数,而inline函数意味着执行前先把调用动作替换为被调用函数的本体,编译器工作在编译期。如果编译器都不知道该调用哪个函数,你也就明白了为啥虚函数不建议设置为inline。更多详情原因请看这里https://www.jianshu.com/p/84a8335444dd
4.糟糕的内联选择:构造函数与析构函数
不要被你的眼睛所欺骗,下面子类构造函数真的是空的吗???
class Base{
public:// ...
private:string bm1, bm2;
};class Derived: public Base{
public:Derived(){} // Derived构造函数真的是空的吗???// ...
private:string dm1, dm2, dm3;
};
当你使用new,动态创建的对象被其构造函数自动初始化;当你使用delete,对应的析构函数会被调用。当你创建一个对象时,基类及其每个成员变量都会被自动构造;当你销毁一个对象时,从子类开始执行析构动作。如果有个异常在对象构造期间抛出,该对象已构造好的那一部分会被自动销毁。你的程序内一定有某些代码让那些事情发生,这些代码即编译器在编译期间产生并安排在你代码中的某个地方。有时候,可能就存在于你的构造函数和析构函数中。上面表面上看起来空的Derived构造函数所产生的代码,如下所示:
Derived::Derived(){Base::Base();try{dm1.string();}catch(...){Base::~Base();throw;}try{dm2.string();}catch(...){dm1.string();Base::~Base();throw;}try{dm3.string();}catch(...){dm2.string();dm1.string();Base::~Base();throw;}
}
上面的代码并不能代表编译器真正产生的代码,因为真正的编译器会以更复杂的做法来处理异常。尽管如此,上面的代码已经能反映Derived的空白构造函数必须提供的行为。不论编译器在其内部所做的异常处理有多么复杂,Derived构造函数至少一定会陆续调用成员变量和基类两者的构造函数,而那些调用会影响编译器是否对此空白函数执行内联动作。
最后,程序库的设计者必须知道:内联函数无法随着程序库的升级而升级。如果fun()是程序库中的一个内联函数,客户将fun()本体编进其程序中,一旦程序库设计者决定改变fun(),所有用到函数f()的客户端程序都必须重新编译。如果fun()是non-inline函数,一旦它有所修改客户端只需要重新连接即可。
对程序开发而言,大部分调试器对内联函数都束手无策,因为你无法在一个并不存在的函数内部设置断点进行调试呢?哪些函数可以设置为inline呢?我的建议是:首先不要将任何函数声明为inline,或者将inline实施范围局限在那些一定可以成为inline的场合。
5.总结
(1) 将大多数inline行为限制在小型、被频繁调用的函数身上。这可以使以后的调试过程和二进制升级更容易,也可以使潜在的代码膨胀问题最小化。
(2) 不要只是因为函数模板出现在头文件中,就将它们声明为inline。
C++语法_深度剖析C++中的inline函数相关推荐
- string类有可以调换方向的函数吗_深度剖析C++中的inline函数
点蓝色字关注"CurryCoder" 微信公众号:CurryCoder的程序人生 怕什么真理无穷,进一寸有一寸的欢喜 1.inline函数的爱恨两难 内联函数比宏优点好很多,详细原 ...
- go test 如何输出到控制台_深度剖析 Go 中的 Go 协程 (goroutines) -- Go 的并发
Go 协程 (goroutine) 是指在后台中运行的轻量级执行线程,go 协程是 Go 中实现并发的关键组成部分. 在上次的课程中,我们学习了 Go 的并发模型.由于 Go 协程相对于传统操作系统中 ...
- 【C语言进阶】带你深度剖析那些常见的字符函数(一)
前言 在C语言的学习中,C语言中对字符和字符串的处理很是频繁,所以今天本文是针对有关字符串的函数进行深度剖析,下面我会介绍函数的功能,如何使用,参数,模拟实现等方面来进行讲述,希望本文对你有所帮助. ...
- matlab里inline定义矩阵,Matlab中的inline函数_matlab中inline函数
Matlab中的inline函数 1.有时为了描述某个数学函数的方便,可以用inline()函数来直接编写该函数,形式相当于M-函数,但无编写一个真正的MATLAB文件,就可以描述出某种数学关系.其调 ...
- 深度卷积神经网络_深度卷积神经网络中的降采样
加入极市专业CV交流群,与6000+来自腾讯,华为,百度,北大,清华,中科院等名企名校视觉开发者互动交流!更有机会与李开复老师等大牛群内互动! 同时提供每月大咖直播分享.真实项目需求对接.干货资讯汇总 ...
- tensorflow中同时两个损失函数_深度度量学习中的损失函数
度量学习(metric learning)研究如何在一个特定的任务上学习一个距离函数,使得该距离函数能够帮助基于近邻的算法(kNN.k-means等)取得较好的性能.深度度量学习(deep metri ...
- pcm 降采样_深度卷积神经网络中的降采样
降采样指的是成比例缩小特征图宽和高的过程,比如从(W,H)变为(W/2,H/2).深度卷积神经网络中降采样的方法主要有三种: 1.stride大于1的pooling 2.stride大于1的conv ...
- 【C++的深度剖析教程21】类型转换函数下
上一篇文章写了关于普通类型转换为类类型的语法与性质,今天我们来看一下:类类型如何转换为普通类型. 一.类型转换函数: C++类中,可以定义类型转换函数,类型转换函数用于将类对象转换为其他类型. 语法规 ...
- python3中input输入浅谈_详解Python3中的 input() 函数
详解Python3中的 input() 函数 一.知识介绍: 1.input() 函数,接收任意输入,将所有输入默认为字符串处理,并返回字符串类型: 2.可以用作文本输入,如用户名,密码框的值输入: ...
- python中len用法_简单介绍Python中的len()函数的使用
简单介绍Python中的len()函数的使用 函数:len() 1:作用:返回字符串.列表.字典.元组等长度 2:语法:len(str) 3:参数:str:要计算的字符串.列表.字典.元组等 4:返回 ...
最新文章
- SAP HUM 因为存在Open TO 单据使得HU不能创建盘点凭证
- 一个基于poi的excel导出程序
- 软件分发、补丁推送排错
- php 获得用户地址吗,php获得用户的真实IP地址_PHP教程
- Exchange 2007 接收zip附件邮件时退信
- 大型网站的架构演进从一个电商网站开始
- python基础-类的继承
- php server 性能,PHP中:$_SERVER[‘REQUEST_TIME’]和 time()有什么区别,那个性能快!...
- Ip绑定域名tomcat配置
- theano学习指南5(翻译)- 降噪自动编码器
- 全球搜索引擎盛会在即 呼叫搜索模式呼之欲出
- linux 去掉登陆密码吗,Linux 清除 Windows用户登录密码
- 13penrose广义逆矩阵(I)
- axure android 原型设计工具,知乎和Quora高分APP原型设计工具推荐
- 向日葵远程控制使用方法
- ubuntu安装linux deepin,如何在ubuntu上安装如何在Ubuntu上安装Deepin桌面环境
- 华为android7.0 root,华为荣耀畅玩6X EMUI5.0 7.0 root教程 荣耀6X获取7.0的root权限
- 华为2019年4月10日实习生笔试题
- React-组件公共逻辑抽离的两种方式
- Android学习日记(yzy):Fragment与VierPager简单实现