天天看点

C++中实际项目开发中的内联函数

        引入内联函数的目的是为了解决程序中函数调用的效率问题,程序在编译器编译的时候,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体进行替换,而对于其他的函数,都是在运行时候才被替代。其实就是用空间的代价去节省时间。

 优点:当函数体比较小的时候,内联该函数可以令目标代码更加高效。 对于存取函数以及其它函数体比较短,,性能关键的函数鼓励使用内联。 

 缺点:滥用内联将导致程序变慢。内联可能使目标代码量或增或减,,这取决于内联函数的大小。内联非常短小的存取函数通常会减少代码大小,但内联一个相当大的函数将戏剧性的增加代码大小。如今的处理器由于更好的利用了指令缓存,小巧的代码往往执行更快。 

         所以内联函数一般都是1-5行的小函数,甚至更少。在实际的项目开发的过程中,通常禁止将最终不会被编译器成功内联的函数定义为内联。因为一旦函数被定义为内联函数,无论该函数最终是否会被成功的内联展开,所有使用了该函数的源文件经过编译后都会有一份该函数的实例,接着再由链接器将这其中冗余的数据整理删除,这个开销是非常大的,会大大延长程序build的时间。

满足以下任一条件的函数都禁止定义为内联函数:

  1. 函数语句超过5行
  2. 含有循环语句
  3. 含有swith语句
  4. 不止一次出现if语句或条件运算符
  5. 特殊的函数:例如递归函数、多态中的虚函数等
        针对上述第五点中的虚函数:如果类中定义了一个内联虚函数,那么仅当编译器在编译阶段确切知道是这个类的对象在调用这个内联虚函数时,才会将该函数内联展开(假设该函数的开销允许它成功内联)。除此以外,通过诸如指针、引用等方式调用该虚函数,编译器在编译阶段时无法知道运行时实际执行的代码是什么,因此绝对不会将该函数内联展开。但在实际的多态开发的环境中,基本都是通过指针、引用之类的方式来调用虚函数。所以,类中定义的内联虚函数就犯了“最终不会被编译器成功内联的函数定义为内联”的错误,因此最好不要将虚函数定义为内联函数。

        inline是实现关键字,不是声明关键字,用在函数声明时是无效的。根据C++编译器的特性,内联函数是无法跨源文件的,被多个源文件使用的内联函数只能同时将声明和定义写在同一个头文件中。如果内联函数的声明和定义分离在不同的文件中,则只有在实现了内联函数的源文件中可以正常使用该内联函数,其它源文件中若调用了该内联函数,在链接阶段会报链接错误,或是由编译器提供一个非内联版本的函数供其它源文件使用,不会真正的展开。 此外,在类内就已经定义完成的函数,即使没有加inline关键字,编译器也会将其隐式定义为内联函数,编译时同一般的内联函数相同处理。

         在常见的C++编译器中,如果编码者没有为某个类提供构造/析构函数,编译器会默认以内联的方式生成这些函数。为没有手动实现构造/析构函数的类实现一个空的、非内联的构造/析构函数,在一定程度上也会减少程序build的时间。

 _forceinline指令: 

        在VC++中可使用另一关键字_forceinline 代替inline 关键字。这个关键字将命令编译器跳过一般的ROI 分析(Return On Investment –一种编程缩略语),将所对应的代码强行内联。有些时候编译器会拒绝将一个函数内联,使用这个关键字,用户只得到一个编译警告,就可强行进行内联。
        但是在实际开发的过程中,从编译和代码膨胀的角度来看,__forceinline是一个非常危险的指令,它修改了编译器对内联函数处理上的默认行为。无论某个函数在开销上是否适合内联,该指令都会命令编译器对这个函数进行强制内联,__forceinline将最终是否成功内联的决定权从编译器转交到了用户手上,且该指令不具备可移植性,因此最好不要使用__forceinline指令。

继续阅读