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

在c++中使用内联函数的优点/缺点是什么?我看到它只增加了编译器输出的代码的性能,但是随着今天优化的编译器,快速的cpu,巨大的内存等(不像在1980<在内存稀缺的情况下,所有东西都必须装入100KB的内存中),它们今天真正有什么优势?

174757 次浏览

内联函数更快,因为你不需要将参数和返回地址等东西推入或弹出堆栈;但是,它确实会使二进制文件略大一些。

有显著的区别吗?对大多数人来说,在现代硬件上还不够明显。但它可以产生影响,这对一些人来说已经足够了。

将某些东西标记为内联并不能保证它将是内联的。这只是给编译器的一个建议。有时候是不可能的比如你有一个虚函数,或者涉及到递归。有时候编译器会选择不使用它。

我可以看到这样的情况会产生明显的不同:

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);

内联是对编译器的一个建议,它可以随意忽略。它非常适合小段代码。

如果你的函数是内联的,它基本上是插入到函数调用的代码中,而不是实际调用一个单独的函数。这有助于提高速度,因为你不必实际打电话。

它还帮助cpu进行流水线操作,因为它们不必用调用引起的新指令重新加载流水线。

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

现在我倾向于把这类决定留给编译器(好吧,至少是聪明的编译器)。编写它们的人往往对底层架构有更详细的了解。

优势

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

缺点

  • 它可以使你的代码更大(例如,如果你使用内联的非平凡函数)。因此,它可能会引起分页并破坏编译器的优化。
  • 它稍微破坏了你的封装,因为它暴露了你的对象处理的内部(但是,每个&;private&;会员也会)。这意味着您不能在PImpl模式中使用内联。
  • 它稍微破坏了您的封装2:c++内联在编译时被解析。这意味着如果您更改了内联函数的代码,您将需要重新编译使用它的所有代码,以确保它将被更新(出于同样的原因,我避免为函数参数设置默认值)
  • 当在头文件中使用时,它会使头文件更大,因此,会用用户不关心的代码稀释有趣的信息(如类方法的列表)(这就是我在类中声明内联函数的原因,但会在类体之后的头文件中定义它,而从不在类体中定义)。

内联魔法

  • 编译器可能内联也可能不内联你标记为内联的函数;它还可以决定在编译或链接时未标记为内联的内联函数。
  • 内联工作就像编译器控制的复制/粘贴,这与预处理器宏有很大的不同:宏将被强制内联,将污染所有的名称空间和代码,将不容易调试,即使编译器认为它是低效的,它也会被执行。
  • 类的每个方法定义在类本身的主体中,都被认为是“内联的”;(即使编译器仍然可以决定不内联它
  • 虚方法不应该是内联的。不过,有时,当编译器可以确定对象的类型(即对象是在同一个函数体中声明和构造的),即使是虚函数也会被内联,因为编译器确切地知道对象的类型。
  • 模板方法/函数并不总是内联的(它们在头文件中的存在不会使它们自动内联)。
  • “内联”之后的下一步;是模板元编程。即通过“内联”;你的代码在编译时,有时,编译器可以推断出一个函数的最终结果…因此,复杂的算法有时可以简化为一种return 42 ;语句。这是为我极端的内联。它在现实生活中很少发生,它使编译时间更长,不会使代码膨胀,并使代码更快。但就像圣杯一样,不要试图将其应用于所有地方,因为大多数处理都不能以这种方式解决……尽管如此,这还是很酷的

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

下面是另一个讨论的结论:

内联函数有什么缺点吗?

显然,使用内联函数并没有什么错。

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

  • 过度使用内联实际上会使程序变慢。根据函数的大小,内联它会导致代码大小的增加或减少。内联一个非常小的访问函数通常会减少代码大小,而内联一个非常大的函数会极大地增加代码大小。在现代处理器上,由于更好地使用指令缓存,较小的代码通常运行得更快。-谷歌指南

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

  • 有一些情况下,内联函数可能不起作用:

    • 对于返回值的函数;如果存在return语句。
    • 对于一个不返回任何值的函数;如果存在循环、switch或goto语句。
    • 如果函数是递归的。
    • 李< / ul > < / >
    • __inline关键字只在指定了优化选项时才会使函数内联。如果指定了optimize, __inline是否被执行取决于内联优化器选项的设置。默认情况下,只要运行优化器,内联选项就会生效。如果你指定了optimize,如果你想忽略__inline关键字,你还必须指定noinline选项。-Source

一般来说,现在任何现代编译器担心内联都是浪费时间。编译器应该通过自己对代码的分析以及您指定的传递给编译器的优化标志来为您优化所有这些注意事项。如果你关心速度,告诉编译器优化速度。如果你关心空间,告诉编译器优化空间。正如另一个答案所暗示的,如果确实有意义,一个好的编译器甚至会自动内联。

另外,正如其他人所说,使用内联并不能保证任何东西都是内联的。如果你想要保证它,你必须定义一个宏而不是一个内联函数来实现它。

何时内联和/或定义宏强制包含?-只有当你对关键代码段的速度有了证明和必要的提高,并且知道这对应用程序的整体性能有影响时。

我想补充一点,在构建共享库时,内联函数是至关重要的。如果不将函数标记为内联,则它将以二进制形式导出到库中。如果导出,它也将出现在符号表中。另一方面,内联函数不会被导出,既不会被导出到库二进制文件中,也不会被导出到符号表中。

当库打算在运行时加载时,它可能是关键的。它还可能打击二进制兼容的库。在这种情况下,不要使用内联。

内联函数是编译器使用的优化技术。可以简单地在函数原型前加上inline关键字来使函数内联。内联函数指示编译器在代码中使用函数的任何地方插入完整的函数体。

优点:- . > . >

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

  2. 它还节省了在堆栈上推/弹出变量的开销,而函数调用。

  3. 它还节省了函数返回调用的开销。

  4. 它利用指令缓存提高了引用的局部性。

  5. 如果指定,内联编译器也可以应用过程内优化。这是最重要的一点,这样编译器现在可以专注于死代码的消除,可以在分支预测,感应变量消除等方面给予更多的重视。

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

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

在古老的C和c++中,inline就像register:给编译器一个关于可能的优化的建议(只不过是一个建议)。

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

如果一个函数(无论多么复杂或“线性”)定义在头文件中,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,链接器将报错

这并不完全是关于性能。c++和C都用于嵌入式编程,位于硬件之上。例如,如果您要编写中断处理程序,则需要确保代码可以立即执行,而不会交换额外的寄存器和/或内存页。这就是内联派上用场的时候。好的编译器在需要速度时自己做一些“内联”,但“内联”迫使它们这样做。

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

为什么不在默认情况下使所有函数内联?因为这是一个工程上的权衡。至少有两种类型的“优化”:加速程序和减少程序的大小(内存占用)。内联通常会加快速度。它消除了函数调用开销,避免从堆栈中推入和拉出参数。然而,这也使程序的内存占用更大,因为现在每个函数调用都必须用函数的完整代码替换。为了使事情变得更加复杂,请记住,CPU将经常使用的内存块存储在CPU上的缓存中,用于超快速访问。如果您使程序的内存映像足够大,那么您的程序将不能有效地使用缓存,在最坏的情况下,内联实际上会降低程序的速度。在某种程度上,编译器可以计算出折衷是什么,并且可能能够做出比您只查看源代码更好的决定。

我们的计算机科学教授敦促我们不要在c++程序中使用内联。当被问及原因时,他友好地向我们解释说,现代编译器应该自动检测何时使用内联。

是的,内联可以是一种优化技术,在任何可能的地方都可以使用,但显然这已经为你做了,只要有可能内联一个函数。