C++内联inline函数失效的几种情况与分析

 
Category: C++

写在前面

参考:

Effective C++ Item30

Inside the C++ Object Model 4.5 inline Functions

gcc之inline关键字(汇编角度查看内联) ;

事实上现代的 C++编译器已经可以智能优化代码了, 并不需要 inline 来刻意处理了, 这里只是为了学习这种历史遗留下来的优化方法以及 inline 的一些可能会失效的情况.

inline 的处理

第一阶段:

分析函数定义, 以决定函数的本质 inline 能力(与编译器相关的能力)

如果函数因为复杂度等原因不能恒伟内敛, 就会被转为一个 static 函数, 并在’被编译模块’内产生对应的函数定义.

第二阶段

真正的 inline 函数扩展操作是在调用的那一点上, 这会带来参数的求值操作以及临时性对象的管理

适用场景

函数体较短

inline 
int my_max(int a, int b) { return b > a ? b : a; }

相当于是宏的一种替代, 安全的实现.

不适用场景

递归函数

即使声明为inline, 也不会展开:

inline 
int my_gcd(int a, int b) { return b ? my_gcd(b, a / b) : a; }

void t1(){
    my_gcd(1,3);
    my_gcd(12,30);
}

通过函数指针调用

不知道调用的是哪个函数, 情况和虚函数类似.

inline 内有局部变量

局部变量:

inline 
int my_max(int a, int b) { 
    int tmp = b > a ? b : a;
    return tmp;
}

此时如果被扩展多次, 就会产生多个局部变量.

inline 传入某些形式参数

这样会导致形式参数导入临时对象(这是为了避免重复求值), 造成资源浪费

inline 
int my_max(int a, int b) { return b > a ? b : a; }

maxval = my_max(foo(), bar() + 1); // 临时对象
// 被展开为:
int t1, t2;
maxval = (t1 = foo()), 
         (t2 = bar() + 1), 
          t2 > t1 ? t2 : t1;

inline 函数内

不要嵌套声明 inline , 造成 inline 函数无法展开的问题. 有点类似递归函数.

函数体较大

这个不用多说了, 如果内联这样的函数会造成代码膨胀.

声明为虚函数

运行期才知道具体执行哪份代码, 所以inline不会在编译期被展开.

构造和析构函数

可能存在异常处理以及展开等情况, 尤其是继承情形. 这时候也不会内联展开