C++内联函数的使用

1、为什么要用内联函数?

在C++中我们通常定义以下函数来求两个整数的最大值:

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

为这么一个小的操作定义一个函数的好处有:

① 阅读和理解函数 max 的调用,要比读一条等价的条件表达式并解释它的含义要容易得多

② 如果需要做任何修改,修改函数要比找出并修改每一处等价表达式容易得多

③ 使用函数可以确保统一的行为,每个测试都保证以相同的方式实现

④ 函数可以重用,不必为其他应用程序重写代码

虽然有这么多好处,但是写成函数有一个潜在的缺点:调用函数比求解等价表达式要慢得多。在大多数的机器上,调用函数都要做很多工作:调用前要先保存寄存器,并在返回时恢复,复制实参,程序还必须转向一个新位置执行

C++中支持内联函数,其目的是为了提高函数的执行效率,用关键字 inline 放在函数定义(注意是定义而非声明,下文继续讲到)的前面即可将函数指定为内联函数,内联函数通常就是将它在程序中的每个调用点上“内联地”展开,假设我们将 max 定义为内联函数:

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

则调用: cout << max(a, b) << endl; 

在编译时展开为: cout << (a > b ? a : b) << endl;  从而消除了把 max写成函数的额外执行开销。

2、内联函数和宏

1、宏容易出错;

2、宏不可调试;

3、宏无法操作类的私有对象;

4、内联函数可以更加深入的优化;

无论是《Effective C++》中的 “Prefer consts,enums,and inlines to #defines” 条款,还是《高质量程序设计指南——C++/C语言》中的“用函数内联取代宏”,宏在C++中基本是被废了,在书《高质量程序设计指南——C++/C语言》中这样解释到:

3. 将内联函数放入头文件

关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。

如下风格的函数 Foo 不能成为内联函数:

inline void Foo(int x, int y);   // inline 仅与函数声明放在一起
void Foo(int x, int y)
{
    //...
} 

而如下风格的函数 Foo 则成为内联函数:

void Foo(int x, int y);
inline void Foo(int x, int y)   // inline 与函数定义体放在一起

所以说,C++ inline函数是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了 inline 关键字,但我认为 inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。

定义在类声明之中的成员函数将自动地成为内联函数,例如:

class A
{
public:
    void Foo(int x, int y) { ... }   // 自动地成为内联函数
} 

但是编译器是否将它真正内联则要看 Foo函数如何定义

内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。

当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。

但是你会很奇怪,重复定义那么多次,不会产生链接错误?

我们来看一个例子:

// 文件A.h 代码如下:
class A
{
public:
    A(int a, int b) : a(a),b(b){}
    int max();
private:
    int a;
    int b;
};
// 文件A.cpp 代码如下:
#include "A.h"
inline int A::max()
{
    return a > b ? a : b;
}
// 文件Main.cpp 代码如下:
#include <iostream>
#include "A.h"
using namespace std;
inline int A::max()
{
    return a > b ? a : b;
}

int main()
{
    A a(3, 5);
    cout << a.max() << endl;
    return 0;
}

一切正常编译,输出结果:5

倘若你在Main.cpp中没有定义max内联函数,那么会出现链接错误: 
error LNK2001: unresolved external symbol "public: int __thiscall A::max(void)" ([email protected]@@QAEHXZ)main.obj 
找不到函数的定义,所以内联函数可以在程序中定义不止一次,只要 inline 函数的定义在某个源文件中只出现一次,而且在所有源文件中,其定义必须是完全相同的就可以。

在头文件中加入或修改 inline 函数时,使用了该头文件的所有源文件都必须重新编译。

4. 慎用内联

“如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?

内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联:

(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。

(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。

类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。”

————《高质量程序设计指南——C++/C语言》 林锐

而在Google C++编码规范中则规定得更加明确和详细:

内联函数:

Tip: 只有当函数只有 10 行甚至更少时才将其定义为内联函数.

定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用. 
优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联. 
缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。 
结论: 一个较为合理的经验准则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 因为有隐含的成员和基类析构函数被调用! 
另一个实用的经验准则: 内联那些包含循环或 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行). 
有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.(递归调用堆栈的展开并不像循环那么简单, 比如递归层数在编译时可能是未知的, 大多数编译器都不支持内联递归函数). 虚函数内联的主要原因则是想把它的函数体放在类定义内, 为了图个方便, 抑或是当作文档描述其行为, 比如精短的存取函数.

-inl.h文件:

Tip: 复杂的内联函数的定义, 应放在后缀名为 -inl.h 的头文件中.

内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义. 然而, 实现代码理论上应该放在 .cc 文件中, 我们不希望 .h 文件中有太多实现代码, 除非在可读性和性能上有明显优势.

如果内联函数的定义比较短小, 逻辑比较简单, 实现代码放在 .h 文件里没有任何问题. 比如, 存取函数的实现理所当然都应该放在类定义内. 出于编写者和调用者的方便, 较复杂的内联函数也可以放到 .h 文件中, 如果你觉得这样会使头文件显得笨重, 也可以把它萃取到单独的 -inl.h 中. 这样把实现和类定义分离开来, 当需要时包含对应的 -inl.h 即可。

原文地址:https://www.cnblogs.com/2018shawn/p/10851779.html

时间: 2024-11-03 18:30:37

C++内联函数的使用的相关文章

关于C++内联函数

关于C++内联函数有以下实验: 有三段测试代码 1.手动展开内联函数. 2.非内联函数. 3.inline标记的内联函数.(函数只有一行代码,以确保函数被内联) 测试三种情况: VS工程在Release版下的有关内联的三个设置选项 1./Ob0 禁用内联展开(默认情况下是打开的). 2./Ob1 只展开标记为 inline 或 __inline 的函数,或在类声明内定义的 C++ 成员函数中的函数. 3./Ob2 展开标记为 inline 或 __inline 的函数和编译器选择的任何其他函数(

java内联函数

在说内联函数之前,先说说函数的调用过程. 调用某个函数实际上将程序执行顺序转移到该函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到  转去执行该函数前的地方.这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保  存地址继续执行.也就是通常说的压栈和出栈.因此,函数调用要有一定的时间和空间方面的开销.那么对于那些函数体  代码不是很大,又频繁调用的函数来说,这个时间和空间的消耗会很大. 那怎么解决这个性能消耗问题呢,这个时候需要引入内联函数了.内联函数

内联函数详解

什么是内联性和外联函数 类的成员函数可以分为内联函数和外联函数.内联函数是指那些定义在类体内的成员函数,即该函数的函数体放在类体内.而说明在类体内,定义在类体外的成员函数叫外联函数.外联函数的函数体在类的实现部分. 内联函数在调用时不是像一般的函数那样要转去执行被调用函数的函数体,执行完成后再转回调用函数中,执行其后语句,而是在调用函数处用内联函数体的代码来替换,这样将会节省调用开销,提高运行速度. 内联函数与前面讲过的带参数的宏定义进行一下比较,它们的代码效率是一样的,但是内联函数要优于宏定义

内联函数的定义及说明

一.什么叫inline函数? inline(小心,不是online),翻译成"内联"或"内嵌".意指:当编译器发现某段代码在调用一个内联函数时,它不是去调用该函数,而是将该函数的代码,整段插入到当前位置.这样做的好处是省去了调用的过程,加快程序运行速度.(函数的调用过程,由于有前面所说的参数入栈等操作,所以总要多占用一些时间).这样做的不好处:由于每当代码调用到内联函数,就需要在调用处直接插入一段该函数的代码,所以程序的体积将增大.拿生活现象比喻,就像电视坏了,通过

宏定义与内联函数

1.宏定义的规则和使用解析(1)宏定义的解析规则就是:在预处理阶段由预处理器进行替换,这个替换是原封不动的替换.(2)宏定义替换会递归进行,直到替换出来的值本身不再是一个宏为止.(3)一个正确的宏定义式子本身分为3部分:第一部分是#dedine ,第二部分是宏名 ,剩下的所有为第三部分.(4)宏可以带参数,称为带参宏.带参宏的使用和带参函数非常像,但是使用上有一些差异.在定义带参宏时,每一个参数在宏体中引用时都必须加括号,最后整体再加括号,括号缺一不可. 宏定义示例1:MAX宏,求2个数中较大的

C++内联函数总结

C++内联函数 Inline函数,看起来像函数,动作像函数,没有宏的副作用,可以调用它们又没有函数调用的额外开销.多好的内联函数 实际上,获得的比想象的还要多,避免函数调用的额外开销只是它好处的一部分而已.编译器还可以通过最优化机制(被设计用来浓缩那些'不含函数调用的代码'的代码),所以当inline某个函数,编译器可能就有能力对它执行语境相关最优化. 但是函数调用会增加目标代码的大小,然而,如果inline函数的本体很小,编译器针对'函数本体'产出的代码可能比'函数调用'产生的目标代码更小.

谈谈 OC 中的内联函数

内联函数 即在编译的时候将函数体替换函数调用,从而不需要将parameter,returnaddress进行push/pop stack的操作, 从而加速app的运行,然而,会增加二进制文件的大小. 疑问:内联函数和非内联函数有很大不同吗? 解答:对硬件硬性不大,但在性能上有影响. 内联函数不能保证编译时候一定是内联的,内联仅仅是告诉编译器请求内联,但编译器不一定内联. 内联函数的使用场景: OC--->结构体CGRectMake--->在快速赋值的时候就是调用了其内联函数 CG_INLINE

内联函数和宏定义的区别

内联函数和宏定义的差别是什么 版权声明:本文为博主原创文章,未经博主允许不得转载.

宏与内联函数

第一部分:宏 为什么要使用宏呢? 因为函数的调用必须要将程序执行的顺序转移到函数所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方.这种转移操作要求在转去执行前要保存现场并记忆执行的地址,转回后要恢复现场,并按原来保存地址继续执行.因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率.而宏只是在预处理的地方把代码展开,不需要额外的空间和时间方面的开销,所以调用一个宏比调用一个函数更有效率. 但是宏也有很多的不尽人意的地方. 在C语言中: 1.宏容易出现一

内联函数

一.什么叫inline函数? inline(小心,不是online),翻译成“内联”或“内嵌”.意指:当编译器发现某段代码在调用一个内联函数时,它不是去调用该函数,而是将该函数的代码,整段插入到当前位置.这样做的好处是省去了调用的过程,加快程序运行速度.(函数的调用过程,由于有前面所说的参数入栈等操作,所以总要多占用一些时间).这样做的不好处:由于每当代码调用到内联函数,就需要在调用处直接插入一段该函数的代码,所以程序的体积将增大.拿生活现象比喻,就像电视坏了,通过电话找修理工来,你会嫌慢,于是