C ++中内联函数的好处?

在C ++中使用内联函数的优点/缺点是什么? 我发现它只会提高编译器输出的代码的性能,但是对于今天优化的编译器,快速的CPU,巨大的内存等(不像1980年<内存稀less,所有内容都适合100KB内存)他们今天真的有优势吗?

内联函数速度更快,因为不需要像堆栈参数和返回地址一样在堆栈上压入/popup东西; 但是,它确实使你的二进制文件稍大一些。

它有重大的不同吗? 对于大多数现代硬件来说,不够明显。 但它可以有所作为,这对一些人来说已经足够了。

在线标记内容并不能保证它是内联的。 这只是编译器的一个build议。 有时候这是不可能的,比如当你有一个虚函数时,或者当涉及到recursion时。 有时编译器只是select不使用它。

我可以看到这样的情况有一个可察觉的区别:

 inline int aplusb_pow2(int a, int b) { return (a + b)*(a + b) ; } for(int a = 0; a < 900000; ++a) for(int b = 0; b < 900000; ++b) aplusb_pow2(a, b); 

优点

  • 通过将您的代码内联到需要的地方,您的程序将花费更less的时间在函数调用和返回部分。 它应该让你的代码更快,即使它变得更大(见下文)。 内联微不足道的访问者可能是有效内联的一个例子。
  • 通过将其标记为内联,可以将一个函数定义放在一个头文件中(也就是说,它可以包含在多个编译单元中,而不需要连接器抱怨)

缺点

  • 它可以使你的代码更大(即如果你使用内联的非平凡function)。 因此,它可能会导致编译器的分页和失败优化。
  • 它稍微打破了封装,因为它暴露了对象处理的内部(但是,每个“私有”成员也是如此)。 这意味着你不能在PImpl模式中使用内联。
  • 它稍微打破了封装2:C ++内联在编译时parsing。 这意味着如果你改变内联函数的代码,你需要使用它来重新编译所有的代码,以确保它会被更新(出于同样的原因,我避免了函数参数的默认值)
  • 在头文件中使用时,会使头文件变大,从而会用用户不关心的代码来稀释感兴趣的信息(如类方法列表)(这是我在内部声明内联函数的原因类,但是将它定义在类体之后的头部中,而不会在类体中)。

内联魔术

  • 编译器可能会也可能不会内联您标记为内联的函数; 它也可能决定内联在编译或链接时没有标记为内联的函数。
  • 内联工作就像由编译器控制的复制/粘贴,这与预处理器macros有很大不同:macros将被强制内联,将污染所有的命名空间和代码,不易debugging,甚至可以完成如果编译器会认定它是低效的。
  • 在类本体内定义的类的每个方法都被认为是“内联的”(即使编译器仍然可以决定不内联
  • 虚拟方法不应该是可以理解的。 尽pipe如此,有时编译器可以确切地知道对象的types(即对象是在同一个函数体内声明和构造的),因为编译器知道对象的types,所以即使虚拟函数也是内联的。
  • 模板方法/函数并不总是内联的(它们在头中的存在不会使它们自动内联)。
  • “inline”之后的下一步是模板元编程。 也就是说,通过在编译时“内联”你的代码,编译器有时候可以推导出函数的最终结果…所以一个复杂的algorithm有时可以简化为一种return 42 ; 声明。 这对我来说是极其重要的 。 它在现实生活中很less发生,它使得编译时间更长,不会膨胀你的代码,并且会使你的代码更快。 但是像圣杯一样,不要试图把它应用到任何地方,因为大多数加工都不能用这种方法来解决…不过,这仍然很酷…
    😛

在陈旧的C和C ++中, inline就像register :一个build议(无非是一个build议)给编译器一个可能的优化。

在现代C ++中, inline告诉链接器,如果在不同的翻译单元中find多个定义(不是声明),它们都是一样的,链接器可以自由地保留一个,并丢弃所有其他的。

如果在头文件中定义了一个函数(无论多么复杂或“线性”), inline是强制性的,以允许多个源包含它而不会由链接器获得“多重定义”错误。

在类中定义的成员函数在默认情况下是“内联的”,就像模板函数一样(与全局函数相反)。

 //fileA.h inline void afunc() { std::cout << "this is afunc" << std::endl; } //file1.cpp #include "fileA.h" void acall() { afunc(); } //main.cpp #include "fileA.h" void acall(); int main() { afunc(); acall(); } //output this is afunc this is afunc 

注意包含fileA.h到两个.cpp文件中,导致afunc()两个实例。 链接器将丢弃其中的一个。 如果没有指定inline ,链接器将会投诉。

内联是对编译器的一个build议,它可以自由地忽略。 这是小部分代码的理想select。

如果你的函数是内联的,它基本上被插入到函数调用的代码中,而不是实际调用一个单独的函数。 这可以提高速度,因为您不必进行实际的呼叫。

它还协助CPU进行stream水线操作,因为它们不必重新加载由呼叫引起的新指令的stream水线。

唯一的缺点是可能增加二进制大小,但只要function很小,这不会太重要。

现在我倾向于把这些决定留给编译器(不pipe怎样,聪明的)。 写他们的人往往对底层架构有更详细的了解。

内联函数是编译器使用的优化技术。 人们可以简单地预先内联关键字函数原型,以使内联函数。 内联函数指示编译器在代码中使用该函数的任何位置插入完整的函数体。

优点 :-

  1. 它不需要函数调用开销。

  2. 它还可以节省堆栈上的variablespush / pop的开销,同时调用函数。

  3. 它还可以节省函数返回的开销。

  4. 它利用指令caching增加了参考的局部性。

  5. 内嵌编译器在指定之后也可以应用程序内优化。 这是最重要的一个,这样编译器现在可以集中在死代码消除上,可以给分支预测,归纳variables消除等更多的压力。

要了解更多信息,可以点击此链接http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html

我想补充一点,在构build共享库时,内联函数是至关重要的。 没有内联标记function,它将以二进制forms输出到库中。 如果输出,它也会出现在符号表中。 另一方面,内联函数不会导出,也不会导出到库二进制文件或符号表中。

当在运行时加载库时,这可能很重要。 它也可能打击二进制兼容感知库。 在这种情况下,不要使用内联。

在优化过程中,即使没有标记,许多编译器也会内联函数。 如果你知道编译器没有的东西,你通常只需要将函数标记为内联函数,因为它通常可以自己做出正确的决定。

inline允许您将函数定义放置在头文件中,并将多个源文件中的头文件包括#include ,而不违反一个定义规则。

一般来说,如今任何现代编译器都担心内嵌任何内容都是浪费时间。 编译器应该通过对代码的自己的分析和传递给编译器的优化标志的规范来实际地优化所有这些注意事项。 如果你关心速度,告诉编译器优化速度。 如果你关心空间,告诉编译器优化空间。 作为另一个答案,一个体面的编译器甚至会自动内联,如果它真的有道理。

另外,正如其他人所说,使用内联不保证任何内联。 如果你想保证它,你将不得不定义一个macros而不是一个内联函数来做到这一点。

何时内联和/或定义macros来强制包含? – 只有当您已经certificate并且必要的已知certificate对应用程序的整体性能具有影响的关键代码部分的速度提高时。

这不是全部关于performance。 C ++和C都用于embedded式编程,位于硬件之上。 例如,如果你想写一个中断处理程序,那么你需要确保代码可以立即执行,而不需要另外的寄存器和/或内存页被交换。 这是内联派上用场的时候。 好的编译器在需要速度的时候做一些“内联”,但是“内联”迫使他们。

在将函数内联到库中的同样的麻烦。 内联函数似乎没有编译到库中。 因此,如果可执行文件想要使用库的内联函数,链接器将发出“未定义的引用”错误。 (碰巧我用gcc 4.5编译Qt源码。

为什么不把默认的所有函数内联? 因为这是一个工程交易。 至less有两种types的“优化”:加速程序并减小程序的大小(内存占用)。 内联通常会加快速度。 它摆脱了函数调用开销,避免从堆栈中拉出参数。 但是,它也会使程序的内存占用更大,因为现在每个函数调用都必须用函数的完整代码来replace。 为了使事情更加复杂,请记住,CPU将经常使用的内存块存储在CPU上的caching中,以便进行超快速访问。 如果程序的内存镜像足够大,程序将无法高效地使用caching,在最坏的情况下,内联可能会减慢程序的速度。 在一定程度上,编译器可以计算出什么是权衡,并且可能能够做出比您更好的决策,只需查看源代码即可。

我们的计算机科学教授要求我们不要在c ++程序中使用内联。 当被问及为什么时,他善意地解释说现代编译器应该检测何时自动使用内联。

所以是的,内联可以是一个优化技术,只要有可能就可以使用,但显然这是已经为你做的事,只要有可能内联一个函数。

从这里的另一个讨论结论:

内联函数有什么缺点吗?

显然,使用内联函数没有任何问题。

但值得注意的是以下几点!

  • 内联过度使用会使程序变慢。 根据函数的大小,内联可能导致代码大小增加或减less。 内联一个非常小的访问函数通常会减less代码的大小,而内联一个非常大的函数会显着增加代码的大小。 在现代处理器上,较小的代码通常由于更好地使用指令caching而运行得更快。 – Google指南

  • 内联函数的速度优势随着函数的增长而趋于减小。 在某些时候,与函数体的执行相比,函数调用的开销变得很小,并且损失了好处- Source

  • 内联函数可能无法正常工作的情况很less:

    • 对于返回值的函数; 如果存在返回语句。
    • 对于不返回任何值的函数; 如果存在循环,开关或goto语句。
    • 如果一个函数是recursion的。 -资源
  • 只有在指定了optimize选项时, __inline inline关键字__inline使函数内联。 如果指定了优化,是否使用__inline取决于内联优化器选项的设置。 默认情况下,内联选项在优化器运行时生效。 如果指定了优化,则如果您希望忽略__inline关键字,还必须指定noinline选项。 -资源