条款 30:透彻了解 inlining 的里里外外

Effective C++ 中文版 第三版》读书笔记

** 条款 30:透彻了解 inlining 的里里外外 **

inline 函数,可以调用它们而又不需蒙受函数调用所招致的额外开销

当你 inline 某个函数,或许编译器就因此又能力对它(函数本体)执行语境相关最优化。

然而,inline 函数背后的整体观念是,将 “对此函数的每一个调用” 都已函数本体替换之,这样做可能增加你的目标码(object code)大小。在内存有限的机器上,过度 inline 会造成程序体积太大,导致换页行为,降低缓存的命中率等一些带来效率损失的行为。

如果 inline 函数的本体很小,编译器针对 “函数本体” 所产生的码可能比针对 “函数调用” 所产出的码更小。将函数 inline 可以导致更小的目标码,从而提高效率。

inline 只是对编译器的一个申请,不是强制命令。这种申请可以隐喻提出也可以明确提出。

隐喻方式是将函数定义于 class 定义式内:

class Person{ 
public: 
    ... 
    int age() const {return theAge;}//一个隐喻的inline申请 
    ... 

private: 
    int theAge; 
};

明确申请 inline 函数的做法是在其定义式前加上关键字 inline。

template<typename T> 

inline const T& std::max(const T& a, const T& b) 
{ 
    return a < b? b: a; 
}

inline 函数通常放置在头文件内,因为大多数建置环境(build environments)在编译过程中进行 inlining,为了将 “函数调用” 替换为 “被调用函数的本体”,编译器必须知道那个函数长什么样子。

templates 通常也被置于头文件内,因为他一旦被引用,编译器(在编译期)为了将它具现化,需要知道它长什么样子。如果 template 没有理由要求它所具现的每个函数都是 inlined,就应该避免将这个 template 声明为 inline(不论显式还是隐式)。inline 需要成本。

大部分编译器拒绝将太过复杂(带有循环或递归)的函数 inlining,而所有对 virtual 函数的调用也都会使 inlining 落空。

有时,虽然编译器有意愿 inlining 某个函数,还是可能为该函数生成一个函数本体。例如,如果程序要取某个 inline 函数的地址,编译器通常必须为此函数生成一个 outlined 函数本体。编译器通常不对 “通过函数指针而进行的调用” 实施 inlining,这意味着对 inline 函数的调用有可能 inlined,也可能不被 inlined:

inline void f(){…}  // 假设编译器有意愿 inline “对 f 的调用”
void (*pf)() = f;
f(); // 这个调用将被 inlined,因为是一个正常调用
pf(); // 这个调用或许不被 inlined,因为通过指针达成有时候编译器生成构造函数和析构函数的 outline 副本,这样他们就可以获得指针指向那些函数,在array内部元素的构造和析构过程中使用。

class base { 
public: 
    ... 
private: 
    std::string bm1, bm2; 
};

class Derived : public Base { 
public: 
    Derived(){}  //Derived 构造函数是空的 是吗? 
    ... 
private: 
    std::string dm1, dm2, dm3; 
};

这个构造函数看起来是 inlining 的绝佳候选人,因为他根本不含任何代码,但是:

C++ 对于 “对象被创建和被销毁时发生什么事” 做了各式各样的保证。编译器为稍早说的那个表面上看起来是空的 Derived 构造函数所产生的代码,相当于以下所列:

Derived::Derived() 
{ 

   Base::Base(); 

    try{dm1.std::string::string();} 

    catch(...){ 

        Base::~Base(); 

        throw; 

    } 

    try{dm2.std::string::string();} 

    catch(...){ 

        dm1.std::string::~string(); 

        Base::~Base(); 

        throw; 

    } 

    try{dm3.std::string::string();} 

    catch(...){ 

        dm2.std::string::~string(); 

        dm1.std::string::~string(); 

        Base::~Base(); 

        throw; 

    } 

}

这段代码并不能代表编译器真正制造出来的代码,但是不论编译器在其内所做的异常处理多么精致复杂,Derived 构造函数至少一定会陆续调用其成员变量和 base class 两者的构造函数,而那些调用(它们自身也可能被 inlined)会影响编译器是否对此空白函数 inlining。

程序库设计者必须评估 “将函数声明为 inline” 的冲击:inline 函数无法随着程序库的升级而升级。f 是程序库内的一个 inline 函数,

客户将 “f 函数本体” 编进其程序中,一旦程序库设计者决定改变 f,所有用到f的客户端程序都必须重新编译。然而若 f 是 non-inline 函数,客户端只要重新连接就好了,如果是程序库采用动态链接,升级后的函数甚至可以不知不觉的被应用程序吸纳。

从实用观点出发,大部分调试器对 inline 函数都束手无策。

请记住:

  1. 将大多数 inline 限制在小型、被频繁调用的函数身上。这可使日后的调试过程和二进制升级更容易,也可以使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。
  2. 不要只因为 function template 出现在头文件中,就将它们声明为 inline。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容