目录

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函数相关推荐

  1. string类有可以调换方向的函数吗_深度剖析C++中的inline函数

    点蓝色字关注"CurryCoder" 微信公众号:CurryCoder的程序人生 怕什么真理无穷,进一寸有一寸的欢喜 1.inline函数的爱恨两难 内联函数比宏优点好很多,详细原 ...

  2. go test 如何输出到控制台_深度剖析 Go 中的 Go 协程 (goroutines) -- Go 的并发

    Go 协程 (goroutine) 是指在后台中运行的轻量级执行线程,go 协程是 Go 中实现并发的关键组成部分. 在上次的课程中,我们学习了 Go 的并发模型.由于 Go 协程相对于传统操作系统中 ...

  3. 【C语言进阶】带你深度剖析那些常见的字符函数(一)

    前言 在C语言的学习中,C语言中对字符和字符串的处理很是频繁,所以今天本文是针对有关字符串的函数进行深度剖析,下面我会介绍函数的功能,如何使用,参数,模拟实现等方面来进行讲述,希望本文对你有所帮助. ...

  4. matlab里inline定义矩阵,Matlab中的inline函数_matlab中inline函数

    Matlab中的inline函数 1.有时为了描述某个数学函数的方便,可以用inline()函数来直接编写该函数,形式相当于M-函数,但无编写一个真正的MATLAB文件,就可以描述出某种数学关系.其调 ...

  5. 深度卷积神经网络_深度卷积神经网络中的降采样

    加入极市专业CV交流群,与6000+来自腾讯,华为,百度,北大,清华,中科院等名企名校视觉开发者互动交流!更有机会与李开复老师等大牛群内互动! 同时提供每月大咖直播分享.真实项目需求对接.干货资讯汇总 ...

  6. tensorflow中同时两个损失函数_深度度量学习中的损失函数

    度量学习(metric learning)研究如何在一个特定的任务上学习一个距离函数,使得该距离函数能够帮助基于近邻的算法(kNN.k-means等)取得较好的性能.深度度量学习(deep metri ...

  7. pcm 降采样_深度卷积神经网络中的降采样

    降采样指的是成比例缩小特征图宽和高的过程,比如从(W,H)变为(W/2,H/2).深度卷积神经网络中降采样的方法主要有三种: 1.stride大于1的pooling 2.stride大于1的conv ...

  8. 【C++的深度剖析教程21】类型转换函数下

    上一篇文章写了关于普通类型转换为类类型的语法与性质,今天我们来看一下:类类型如何转换为普通类型. 一.类型转换函数: C++类中,可以定义类型转换函数,类型转换函数用于将类对象转换为其他类型. 语法规 ...

  9. python3中input输入浅谈_详解Python3中的 input() 函数

    详解Python3中的 input() 函数 一.知识介绍: 1.input() 函数,接收任意输入,将所有输入默认为字符串处理,并返回字符串类型: 2.可以用作文本输入,如用户名,密码框的值输入: ...

  10. python中len用法_简单介绍Python中的len()函数的使用

    简单介绍Python中的len()函数的使用 函数:len() 1:作用:返回字符串.列表.字典.元组等长度 2:语法:len(str) 3:参数:str:要计算的字符串.列表.字典.元组等 4:返回 ...

最新文章

  1. SAP HUM 因为存在Open TO 单据使得HU不能创建盘点凭证
  2. 一个基于poi的excel导出程序
  3. 软件分发、补丁推送排错
  4. php 获得用户地址吗,php获得用户的真实IP地址_PHP教程
  5. Exchange 2007 接收zip附件邮件时退信
  6. 大型网站的架构演进从一个电商网站开始
  7. python基础-类的继承
  8. php server 性能,PHP中:$_SERVER[‘REQUEST_TIME’]和 time()有什么区别,那个性能快!...
  9. Ip绑定域名tomcat配置
  10. theano学习指南5(翻译)- 降噪自动编码器
  11. 全球搜索引擎盛会在即 呼叫搜索模式呼之欲出
  12. linux 去掉登陆密码吗,Linux 清除 Windows用户登录密码
  13. 13penrose广义逆矩阵(I)
  14. axure android 原型设计工具,知乎和Quora高分APP原型设计工具推荐
  15. 向日葵远程控制使用方法
  16. ubuntu安装linux deepin,如何在ubuntu上安装如何在Ubuntu上安装Deepin桌面环境
  17. 华为android7.0 root,华为荣耀畅玩6X EMUI5.0 7.0 root教程 荣耀6X获取7.0的root权限
  18. 华为2019年4月10日实习生笔试题
  19. React-组件公共逻辑抽离的两种方式
  20. Android学习日记(yzy):Fragment与VierPager简单实现

热门文章

  1. Hadoop运行时缺少hadoop dll winutils exe
  2. Linux命令(五)之service服务查找、启动/停止等相关操作
  3. 《学习之道》第六章补充
  4. 为什么快速排序比归并排序快
  5. Android SDK 更新时修改hosts文件仍然无法更新,可试试这个方法……
  6. VS2010启动总是遇到异常提示的解决
  7. winsock错误一览表
  8. 一段获取视频的简易方法
  9. win10系统下如何查看端口被哪个进程占用
  10. Java面试题超详细讲解系列之九【SQL语句篇】