C++箴言:理解inline化的介入和排除

inline 函数——多么棒的主意啊!它们看起来像函数,它们产生的效果也像函数,它们在各方面都比宏好得太多太多,而你却可以在调用它们时不招致函数调用的成本。你还有什么更多的要求呢?

实际上你得到的可能比你想的更多,因为避免函数调用的成本只是故事的一部分。在典型情况下,编译器的优化是为了一段连续的没有函数调用的代码设计的,所以当你 inline 化一个函数,你可能就使得编译器能够对函数体实行上下文相关的特殊优化。大多数编译器都不会对 "outlined" 函数调用实行这样的优化。

然而,在编程中,就像在生活中,没有免费午餐,而 inline 函数也不例外。一个 inline 函数背后的思想是用函数本体代替每一处对这个函数的调用,而且不必拿着统计表中的 Ph.D. 就可以看出这样可能会增加你的目标代码的大小。在有限内存的机器上,过分热衷于 inline 化会使得程序对于可用空间来说过于庞大。即使使用了虚拟内存,inline 引起的代码膨胀也会导致附加的分页调度,减少指令缓存命中率,以及随之而来的性能损失。

在另一方面,如果一个 inline 函数本体很短,为函数本体生成的代码可能比为一个函数调用生成的代码还要小。如果是这种情况,inline 化这个函数可以实际上导致更小的目标代码和更高的指令缓存命中率! 记住,inline 是向编译器发出的一个请求,而不是一个命令。这个请求能够以显式的或隐式的方式提出。隐式的方法就是在一个类定义的内部定义一个函数:

class Person {
  public:
   ...
   int age() const { return theAge; } // an implicit inline request: age is
   ... // defined in a class definition
  private:
   int theAge;
};


这样的函数通常是成员函数,不过我们知道友元函数也能被定义在类的内部,如果它们在那里,它们也被隐式地声明为 inline。

显式的声明一个 inline 函数的方法是在它的声明之前加上 inline 关键字。例如,以下就是标准 max 模板(来自 )经常用到的的实现方法:

template // an explicit inline
inline const T& std::max(const T& a, const T& b) // request: std::max is
{ return a < b ? b : a; } // preceded by "inline"


max 是一个模板的事实引出一个观察结论:inline 函数和模板一般都是定义在头文件中的。这就使得一些程序员得出结论断定函数模板必须是 inline。这个结论是非法的而且有潜在的危害,所以它值得我们考察一下。 inline 函数一般必须在头文件内,因为大多数构建环境在编译期间进行 inline 化。为了用被调用函数的函数本体替换一个函数调用,编译器必须知道函数看起来像什么样子。(有一些构建环境可以在连接期间进行 inline 化,还有少数几个——比如,基于 .NET Common Language Infrastructure (CLI) 的控制环境——居然能在运行时 inline 化。然而,这些环境都是例外,并非规则。inline 化在大多数 C++ 程序中是一个编译时行为。)

模板一般在头文件内,因为编译器需要知道一个模板看起来像什么以便用到它时对它进行实例化。(同样,也不是全部如此。一些构建环境可以在连接期间进行模板实例化。然而,编译期实例化更为普遍。) 模板实例化与 inline 化无关。如果你写了一个模板,而且你认为所有从这个模板实例化出来的函数都应该是 inline 的,那么就声明这个模板为 inline,这就是上面的 std::max 的实现被做的事情。但是如果你为没有理由要 inline 化的函数写了一个模板,就要避免声明这个模板为 inline(无论显式的还是隐式的)。inline 化是有成本的,而且你不希望在毫无预见的情况下遭遇它们。我们已经说到 inline 化是如何引起代码膨胀的,但是,还有其它的成本,过一会儿我们再讨论。

时间: 2024-09-18 03:32:34

C++箴言:理解inline化的介入和排除的相关文章

如何理解语义化的html结构

HTML结构是页面的骨架,一个页面就好像一幢房子,HTML结构就是钢精钢筋混泥土的墙,一幢房子如果没有钢精钢筋混泥土的墙那就是一堆费砖头,不能住人,不能办公. 相信大家都知道html和css,知道html结构和css表现分离,知道html语义化,这些都是这几年的热门关键字.语义化的html在国内也是一两年前才开始被追捧的,看看现在群里谈论的html结构,关于html结构的面试题,语义化的html占据了很大一部分.那么为什么要使用语义化的HTML?语义化的HTML到底有什么好处呢? HTML是提供

腾讯发表声明否认马化腾介入阿Sa婚姻

深圳特区报讯 昨日,腾讯公司发表声明,就连日来其董事会主席兼CEO马化腾卷入香港艺人阿Sa和郑中基离婚一事作出回应.该公司否认马化腾以"第三者"身份介入阿Sa婚姻,并称其将严肃对待此事,拟采取法律行动进行维权. 此前,香港某周刊就连日来轰动一时的阿Sa和郑中基离婚一事进行报道.文章称阿Sa和郑中基在一起四年,两人因郑中基花心导致关系紧张已久.后阿Sa在工作中结识马化腾并产生感情.(汪言)

软件架构设计箴言理解

     今天和师弟聊天聊到他们项目开发,有些同事总是提前考虑性能优化,需求变更又是一大堆的重写,让我想起了Donald Knuth 提到的:对软件的过早地优化是万恶的根源.这里就简单的说几条重要的软件名人哲学. 1:软件中唯一不变的就是变化.      在软件开发过程中需求是不停的变化,随着客户对系统的认识,和现有开发功能和软件的认识,也许以开始他提出的需求就是背离的.记得网上有一句笑话,师说需求变化的:   程序员XX遭遇车祸成植物人,医生说活下来的希望只有万分之一,唤醒更为渺茫.可他的Le

港媒爆马化腾介入阿Sa婚姻腾讯称其无中生有

日前,香港<壹周刊>报道称,近日宣布办理离婚手续的阿Sa.郑中基,失和的主要原因是阿Sa和腾讯老总马化腾过从甚密,最后浓情转淡直至分道扬镳. 对此,阿Sa经纪人不愿意回应,只说搞不好马先生根本不认识阿Sa,从而间接否认这个消息:而昨日腾讯公司更在腾讯网首页发表声明,称港媒捏造并拟采取法律行动. 据<壹周刊>报道,阿Sa2008年就曾经在工作上和马化腾有过合作,去年7月正式认识,11月传出秘密交往,该周刊还绘声绘影描述两人过从甚密,甚至还说阿Sa 曾经向男方抱怨郑中基出轨. 本报综合

腾讯否认马化腾介入阿Sa婚姻

新快报记者贺雅佳 阿Sa经纪人霍汶希:"阿Sa不认识马化腾,请你去问对方认不认识阿Sa,传闻越来越夸张.阿Sa情绪低落没法彩排要休息." Sa爸:"哈哈--谢谢!我没什么回应呀,有空请你们吃饭呀." 腾讯公司严正声明 昨日(3月31日)香港<壹周刊>凭空捏造有关腾讯公司董事会主席兼CEO马化腾先生的报道,完全无中生有,严重违背传媒道德.腾讯公司对此捏造行为将严肃对待,并对该媒体采取必要的法律行动. 腾讯公司 2010年4月1日 阿Sa和郑中基自从宣布离婚

M2M将享两化融合红利2010年扩大试点范围

(记者 杨志杰 王侠)2010年,两化融合由地方试验升级为国家示范,在这一趋势中,三大运营商有望享受众多资金.政策红利. 1月20日到21日,工业和信息化部在广东佛山召开了国家两化融合试验区工作会议,指出2010年是两化融合试验区三年试点工作目标能否实现的关键年,要求各地按照"调结构.上水平.保持工业经济平稳较快发展"的总体思路,推进试验区工作向纵深发展. 目前,我国经济呈现出企稳回升态势,但是经济发展中依然存在着产业结构不合理.竞争力和自主创新能力不强.资源与环境制约严重等问题.信息

【原】常见的模块,你语义化了没

记得在读大学期间,去找实习,面试时被问到"什么是标签的语义化",一头汗水,也忘记那时是怎么瞎扯了,后来回宿舍,上网查"标签语义化",当时的网络对标签语义化的解释并不多,在找了很多网络资料和书籍后才对语义化有一定的了解.现在标签语义化这个专业名字,在前端开发的领域中已经不陌生了. 什么是标签语义化?为什么要标签语义化?如何语义化标签?这是一名合格的前端开发工程师需要思考的.<HTML标签语义化对照表>解释了HTML标签的语义,有助于大家理解语义化,<

如何将「插件化」接入到项目之中?

本期移动开发精英社群讨论的主题是「插件化」,上网查了一下,发现一篇 CSDN 博主写的文章<Android 使用动态加载框架DL进行插件化开发>.此处引用原作者的话: 随着应用的不断迭代,应用的体积不断增大,项目越来越臃肿,冗余增加.项目新功能的添加,无法确定与用户匹配性,发生严重异常往往牵一发而动全身,只能紧急发布补丁版本,强制用户进行更新.结果频繁的更新,反而容易降低用户使用黏性,或者是公司业务的不断发展,同系的应用越来越多,传统方式需要通过用户量最大的主项目进行引导下载并安装.怎么办?这

C++实现inline hook的原理及应用实例_C 语言

本文实例简述了C++实现inline hook的原理及应用,对于大家更好的理解inline hook原理及其应用有很大的帮助.具体内容如下: 一.Inline Hook简介: 1.INLINE HOOK原理: Inline Hook通过硬编码的方式向内核API的内存空间(通常是开始的一段字节,且一般在第一个call之前,这么做是为了防止堆栈混乱)写入跳转语句,这样,该API只要被调用,程序就会跳转到我们的函数中来,我们在自己写的函数里需要完成3个任务: 1)重新调整当前堆栈.程序流程在刚刚跳转的