Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5784962
  • 博文数量: 291
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 7924
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-06 14:28
个人简介

阿里巴巴是个快乐的青年

文章分类

全部博文(291)

文章存档

2018年(21)

2017年(4)

2016年(5)

2015年(17)

2014年(68)

2013年(174)

2012年(2)

分类: C/C++

2013-07-01 17:26:48

        inline函数很潇洒,它看起来像函数,动作也像函数,但是调用它时又不需要蒙受函数调用所带来的额外开销,达到宏的性能而使用效果却好得多
        但是天下没有免费的午餐,inline函数在潇洒背后也有辛酸,inline函数的原理是编译器将“对此函数的每一个调用”都以函数本地替换之,由此可能带来的负面效应是增加目标码(object code)的大小。
        在一台内存有限的机器上,过度热衷inlining会造成程序体积太大,即使拥有虚拟内训,inline造成的代码膨胀亦会导致额外的换页行为(paging),降低指令高速缓存装置的命中率,以及伴随这些而来的效率损失。这一点尤其在目前炙手可热的移动开发来说很重要。
        换个角度说,如果inline函数的本体很小,编译器针对“函数本体”所产出的码可能比针对“函数调用”所产出的码更小,果真如此,将函数inlining确实可能导致较小的目标码和较高的指令高速缓存命中率。
        需要注意的是:inline只是对编译器的一个申请,而不是强制命令。这项申请可以隐喻提出,也可以明确提出。隐喻方式是将函数定义于class定义式内:
        class Person {
        public:
                ...
                int age() const {return theAge;}        //一个隐喻的inline申请,age被定义于class定义式内
                ...
        private:
                int theAge;
        };
        明确声明inline函数的做法则是在其定义式前加上关键字inline,例如标准的max template的实现就是:
        template
        inline const T& std::max(const T& a, const T& b)        //一个明确的inline申请,std::max之前有关键字“inline”
        { return a > b ? b : a;}
        大部分编译器拒绝将太过复杂(例如带有循环或递归)的函数inlining,而所有对virtual函数的调用(除非是最平淡无奇的)也都会使inlining落空,因为virtual意味着“等待,直到运行期才确定调用哪个函数”,而inline意味着“执行前,先将调用动作替换为被调用函数的本体”。如果编译器不知道该调用哪个函数,那就别怪它无情地拒绝将函数本体inlining了。但是也不要为此感到沮丧,幸运的是大多数编译器会在无法将你要求的函数inline化时给你一个警告信息,够哥们儿了。此外,对于通过函数指针调用的函数不会被inlining,因为编译器没有能力提出一个指针指向并不存在的函数。
        还是那句话天下没有免费的午餐,inline函数带来好处的同时也会有副作用:inline函数无法随着程序库的升级而升级。换句话说:如果某个函数f是程序库内的一个inline函数,客户将”f函数本体“编进其程序中了,一旦程序库设计者决定改变f,所有用到f的客户端程序都必须重新编译。如果f是non-inline函数,且在动态库中,则升级版函数会不知不觉地被应用程序吸纳。此外,有很多调试器不支持在inline函数中设置断点,因为此时函数并不存在。
        总结来了:将大不多数inlining限制在小型、被频繁调用的函数身上,这可使日后的调试过程和二进制升级更容易,也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。
      




        
阅读(2227) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~