Effective C++ 条款30 透彻了解inlining的里里外外

1. inline函数既和带参宏一样不带来函数调用的额外开销,又具有和非inline函数相同的功能,也就是说,inline函数同时具备带参宏和非inline函数的优点.

此外,编译器优化机制通常针对于那些不含参数调用的代码,因此inline某个函数就有可能使编译器对它执行语句相关最优化.

2. 虽然inline函数有诸多优点,但由于inline函数对每一次函数调用都用函数本体替换,这无疑加重了编译负担,更重要的是它增加了代码量,此外,由于inline造成的代码膨胀"会导致额外的换页行为(paging),降低指令高速缓存装置的击中率(instruction cache hit rate)",以致增加效率损失.当然,如果inline函数的本体很小,编译器所产出的码可能比函数调用的码更小,将函数inline反而可以导致较小的目标码和较高的指令高速缓存装置击中率.

此外,将函数声明为inline可能会带来其他副作用:"inline函数无法随着程序库的升级而升级",如果程序库内的某个inline函数需要被更改,那么所有用到该函数的代码都需要被重新编译(如果该函数是非inline函数,只要函数借口不变,客户端只需重新链接即可.如果使用动态链接,"升级版函数甚至可以不知不觉地被应用程序吸纳").

3. inline只是对编译器的一个申请,并不是强制命令,编译器对代码量复杂的函数(例如循环或递归),virtual函数(必须在执行期才能决定本体)拒绝展开(并会产生警告).此外,inline函数也可以隐喻提出,在类中定义的函数默认被声明为inline(由于友元函数也可以在类内部定义,这样的友元函数也被声明为inline函数).

注:头文件中只能有声明,而不能有定义,只有三个例外:类定义,inline函数,const变量.只有类的前置声明无法构造类对象,因此头文件中一定要有类的定义,inline函数类似,要将函数展开就一定要看到函数本体,因此inline函数通常被置于头文件中.

4. 即使编译器同意inline某个函数,但有时同样也会为该函数生成一个函数本体,例如程序要取一个inline函数的地址,此时编译器虽然将函数inline,但还是为产生了本体.此外,编译器通常不对"通过函数指针进行的调用"实施inlining,这意味着"对inline函数的调用有可能被inline,也有可能不被inline,取决于该调用的实施方式".即使不使用函数指针,编译器依然可能为构造函数和析构函数生成outline副本,以便于获取指针而在array内部元素的构造和析构中使用

5. 此外,有些函数看起来代码量很小,但编译器可能在其中插入了大量代码(为了支持面向对象这经常发生),例如对于一个继承层次中的底层派生类,其构造函数需要包含整个继承层次中的基类的构造函数以及它的成员对象的构造函数,这些都是在编译器被插入的.同理,析构函数也是如此.因此,是否将构造函数和析构函数inline也应当被慎重考虑.

6. 除了以上所提,有一个事实更加重要:"大部分调试器对inline函数束手无策",毕竟无法在一个不存在的函数内设置断点(break-point),"虽然有些某些建置环境勉力支持对inlined函数的调试,其他许多建置环境仅仅只能‘在调试版程序中禁止发生inlining"‘.因此一开始不要将任何函数都声明为inline,或至少仅将那些"一定要成为inline"或"十分平淡无奇"的函数神上,尽管这也将自己推向手工最优化之路.

时间: 2024-10-12 22:57:59

Effective C++ 条款30 透彻了解inlining的里里外外的相关文章

[Effective C++系列]-透彻了解inlining的里里外外

Understand the ins and outs of inlining. [原理] Inline函数背后的做法是将“对函数的每一个调用”都用函数本体替换之.其好处是: 可以消除函数调用所带来的开销. 编译器最优化机制通常被设计用来浓缩那些“不含函数调用”的代码,因此当你inline某个函数,或许编译器有能力对它(函数本体)执行语境相关最优化.大部分编译器不会为一个“outlined函数调用”执行这种最优化动作. 然而inline函数这些美好的一面也伴随着代价:inline函数可能增加程序

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

(一) inline函数,可以调用它们而又不需蒙受函数调用所招致的额外开销. inline函数背后的整体观念是,将"对此函数的每一个调用"都已函数本体替换之,这样做可能增加你的目标码(object code)大小.在内存有限的机器上,过度inline会造成程序体积太大,导致换页行为,降低缓存的命中率等一些带来效率损失的行为.如果inline函数的本体很小,编译器针对"函数本体"所产生的码可能比针对"函数调用"所产出的码更小.将函数inline可以

《Effective C++》:条款30:透彻了解inlining的里里外外

inline函数为什么放到头文件 inline函数是特殊的函数,它有宏的优点,却克服了宏的缺点(**条款**2).inline函数可以免除函数调用所招致的额外开销,但你实际获得的好处可能比你想象的还多,编译器会对inline函数本体执行语境相关最优化. 但使用inline函数会导致目标码(object code)变大,因为对inline函数的调用都会以函数本体替换.在内存比较小的机器上,不宜过多使用inline函数.即使使用虚拟内存,也会导致额外的换页行为(paging),降低指令高速缓存装置的

More Effective C++ 条款30 Proxy classes(替身类,代理类)

1. 所谓代理类(proxy class),指的是"它的每一个对象都是为了其他对象而存在的,就像是其他对象的代理人一般".某些情况下用代理类取代某些内置类型可以实现独特的功能,因为可以为代理类定义成员函数而但却无法对内置类型定义操作.条款5就展示了一个使用代理类阻止隐式类型转换的例子. 2. 实现二维数组. C++没有提供分配动态二维数组的语法,因此常常需要定义一些类(模板实现这些功能),像这样: template<class T> class Array2D { publ

[Effective C++ --030]透彻了解inlining的里里外外

引言  inline函数 在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联. inline函数对编译器而言必须是可见的,以便它能够在调用点内展开该函数.与非inline函数不同的是,inline函数必须在调用该函数的每个文本文件中定义.当然,对于同一程序的不同文件,如果inline函数出现的话,其定义必须相同. 为保证不会发生这样的事情,建议把inline函数的定义放到头文件中.在每个调用该inline函数的文件中包含该头文件.这种方法保证对每个inline函数只有

读书笔记 effective c++ Item 30 理解内联的里里外外 (大师入场啦)

最近北京房价蹭蹭猛涨,买了房子的人心花怒放,没买的人心惊肉跳,咬牙切齿,楼主作为北漂无房一族,着实又亚历山大了一把,这些天晚上睡觉总是很难入睡,即使入睡,也是浮梦连篇,即使亚历山大,对C++的热情和追求还是不减,应该是感动了周公吧,梦境从此处开始,大师入场来给我安慰了... 11点躺在床上了,脑子里总结一下最近的工作:最近的开发用到inline函数比较多,众所周知,inline的使用是为了提高程序性能,可结果却总不尽如人意,这个捉急啊,嗯?怎么突然到了山脚下,周边树木林立,郁郁葱葱,鸟儿委婉啼叫

《Effective C++》学习笔记——条款30

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 五.Implementations Rule 30:Understand the ins and outs of inlining 规则 30:透彻了解inlining的里里外外 1.inline 的优缺点 > 优点 --看起来像函数 --动作像函数 --比宏好

effective c++条款26-31“class and function的实现”整理

一.类的实现面临的问题: 太快定义变量可能造成效率上的拖延:过度使用转型(casts)可能导致代码变慢又难维护,又招来微妙难解的错误:返回对象"内部数据之号码牌(handls)"可能会破坏封装并留给客户虚吊号码牌:为考虑异常带来的冲击则可能导致资源泄漏和数据败坏:过度热心地inlining可能引起代码膨胀:过度耦合则可能导致让人不满意的冗长建置时间. 二.条款26:尽可能延后变量定义式的出现时间 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被

effective c++ 条款18 make interface easy to use correctly and hard to use incorrectly

举一个容易犯错的例子 class Date { private: int month; int day; int year; public: Date(int month,int day,int year) { this->month = month; ... } } //wrong example Date date(30,3,1995);//should be 3,30 Date date(2,30,1995);//should be 3,30 使用类型可避免这个问题 class Month