关于c ++:使用内联函数有什么问题?

关于c ++:使用内联函数有什么问题?

What is wrong with using inline functions?

虽然在某些情况下使用内联函数会非常方便,

内联函数有什么缺点吗?

结论:

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

但是值得注意以下几点!

  • 内联的过度使用实际上会使程序变慢。根据函数的大小,对其内联会导致代码大小增加或减少。内联非常小的访问器函数通常会减小代码大小,而内联非常大的函数则会大大增加代码大小。在现代处理器上,由于更好地使用了指令缓存,因此较小的代码通常可以更快地运行。 -Google指南

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

  • 内联函数在某些情况下可能不起作用:

    • 对于返回值的函数;如果存在return语句。
    • 对于不返回任何值的函数;如果存在循环,开关或转到语句。
    • 如果函数是递归的。 -资源
  • __inline关键字仅在指定optimize选项时才使函数内联。如果指定了optimize,则是否采用__inline取决于内联优化器选项的设置。默认情况下,只要运行优化器,内联选项就会生效。如果指定optimize,那么如果要忽略__inline关键字,还必须指定noinline选项。 -资源


值得指出的是,inline关键字实际上只是对编译器的提示。编译器可能会忽略内联,而只是在某个地方为该函数生成代码。

内联函数的主要缺点是它会增加可执行文件的大小(取决于实例化的数量)。在某些平台(例如嵌入式系统)上,这可能是个问题,特别是如果函数本身是递归的。

我还建议使内联函数非常小-内联函数的速度优势会随着函数大小的增加而逐渐减少。在某些时候,与函数主体的执行相比,函数调用的开销变小,并且失去了好处。


可能会增加
可执行文件,我不认为
编译器将始终使
即使您使用了
内联关键字。 (还是其他
像Vaibhav一样
说过?...)

我认为通常可以
函数只有1或2条语句。

编辑:这是linux CodingStyle文档关于它的内容:

Chapter 15: The inline disease

There appears to be a common
misperception that gcc has a magic
"make me faster" speedup option called
"inline". While the use of inlines can
be appropriate (for example as a means
of replacing macros, see Chapter 12),
it very often is not. Abundant use of
the inline keyword leads to a much
bigger kernel, which in turn slows the
system as a whole down, due to a
bigger icache footprint for the CPU
and simply because there is less
memory available for the pagecache.
Just think about it; a pagecache miss
causes a disk seek, which easily takes
5 miliseconds. There are a LOT of cpu
cycles that can go into these 5
miliseconds.

A reasonable rule of thumb is to not
put inline at functions that have more
than 3 lines of code in them. An
exception to this rule are the cases
where a parameter is known to be a
compiletime constant, and as a result
of this constantness you know the
compiler will be able to optimize most
of your function away at compile time.
For a good example of this later case,
see the kmalloc() inline function.

Often people argue that adding inline
to functions that are static and used
only once is always a win since there
is no space tradeoff. While this is
technically correct, gcc is capable of
inlining these automatically without
help, and the maintenance issue of
removing the inline when a second user
appears outweighs the potential value
of the hint that tells gcc to do
something it would have done anyway.


内联有一个问题-一旦您在头文件中定义了一个函数(通过在类内部定义成员函数的主体来暗示内联,无论是显式的还是隐式的),就没有简单的方法来更改它而不会强迫用户重新编译(而不是重新链接)。通常这会引起问题,特别是如果所讨论的函数在库中定义并且标头是其接口的一部分时,尤其如此。


就像其他人提到的那样,inline关键字只是对编译器的提示。实际上,大多数现代编译器将完全忽略此提示。编译器有自己的启发式方法来决定是否内联函数,并且坦率地说,我们不希望您提出建议,非常感谢。

如果您确实确实想进行内联,如果您已经对它进行了概要分析并查看了反汇编以确保重写编译器启发式方法确实有意义,那么可以这样做:

  • 在VC ++中,使用__forceinline关键字
  • 在GCC中,使用__attribute __((always_inline))

但是,inline关键字确实具有第二个有效目的-在头文件中声明函数,但不在类定义中声明函数。需要inline关键字来告诉编译器不要生成该函数的多个定义。


我同意其他职位:

  • 内联可能是多余的,因为编译器会这样做
  • 内联可能会使您的代码肿

第三点是,它可能会迫使您在标头中公开实现细节,例如,

1
2
3
4
5
6
7
8
class OtherObject;

class Object {
public:
    void someFunc(OtherObject& otherObj) {
        otherObj.doIt(); // Yikes requires OtherObj declaration!
    }
};

如果没有内联,则只需要一个OtherObject的前向声明即可。与内联您
标头需要OtherObject的定义。


我不知道我的答案是否与问题有关,但:

内联虚拟方法要非常小心!一些错误的编译器(例如,Visual C ++的早期版本)会为虚拟方法生成内联代码,这些虚拟方法的标准行为是不做任何事情,而只继承继承树并调用适当的方法。


我对此表示怀疑。甚至编译器也会自动内联某些函数以进行优化。


内联较大的函数可以使程序更大,从而导致更多的高速缓存未命中并使其速度变慢。

确定何时函数足够小以内联将提高性能非常困难。 Google的C ++样式指南建议仅内联10行或更少行的函数。


您还应该注意,内联关键字只是一个请求。编译器可能选择不内联它,同样,如果编译器认为速度/大小的折衷是值得的,则可以选择使未定义为内联的函数内联。

通常,此决定是基于许多因素做出的,例如在优化速度(避免调用函数)和优化大小(内联会导致代码膨胀,因此对于大型重复使用的函数而言不是很大)之间进行设置。

使用VC ++编译器,您可以使用__forceinline覆盖此决定

一般而言:
如果您确实想在标头中包含一个函数,请使用内联,但是在其他地方没有什么意义,因为如果您要从中获得任何东西,一个好的编译器无论如何都会使其内联。


内联函数的其他问题(我已经看到过分使用过(我见过500行的内联函数)),您需要注意的是:

  • 建立不稳定

    • 更改内联函数的源将导致标头的所有用户重新编译
    • #include泄漏到客户端。如果您对内联函数进行重新处理并删除某些客户端所依赖的不再使用的标头,这可能会很讨厌。
  • 可执行文件大小

    • 每次内联而不是调用指令都被内联时,编译器必须生成内联的整个代码。如果该函数的代码很短(一两行),就可以了,如果该函数的代码很长,那么就没那么好了
    • 有些功能可以产生比最初出现更多的代码。举例来说,一个类的"琐碎"析构函数具有很多非Pod成员变量(或者两个或3个成员变量具有相当混乱的析构函数)。必须为每个析构函数生成一个调用。
  • 执行时间处理时间

    • 这非常取决于您的CPU缓存和共享库,但是引用的位置很重要。如果您可能要内联的代码恰好保存在一个位置的cpu缓存中,那么许多客户端可以发现该代码不会遭受缓存未命中和随后的内存提取(更糟糕的是,如果发生磁盘提取) 。不幸的是,这是您真正需要进行性能分析的情况之一。

我工作的编码标准将内联函数限制为简单的setter / getter,特别是说析构函数不应为内联,除非您进行性能测量以显示内联具有明显的优势。


函数过多的内联会增加编译后的可执行文件的大小,这可能会对缓存性能产生负面影响,但如今,编译器自行决定对函数进行内联(取决于许多条件),而忽略inline关键字。


  • 正如其他人所说的那样,如果代码很大,则内联函数可能会产生问题。由于每条指令都存储在特定的内存位置中,因此内联函数的重载会使代码花费更多的时间被淘汰。

  • 在其他情况下,内联可能不起作用

  • 在递归函数的情况下不起作用。
  • 它也可能不适用于静态变量。
  • 在使用循环,开关等的情况下也不起作用,或者可以说有多个语句。
  • 并且函数main不能用作内联函数。

  • 推荐阅读