使用内联函数有什么问题?
虽然在某些情况下使用内联函数会非常方便,但是
内联函数有什么缺点吗?
结论:
显然,使用内联函数没有任何问题。
但值得注意的是以下几点!
过度使用内联实际上会使程序变慢。 根据函数的大小,内联它可能会导致代码大小增加或减少。 内联一个非常小的访问器函数通常会减少代码大小,而内联一个非常大的函数会显着增加代码大小。 在现代处理器上,由于更好地利用指令缓存,较小的代码通常运行得更快。 - Google 指南
内联函数的速度优势往往随着函数规模的增大而减小。 在某些时候,与函数体的执行相比,函数调用的开销变得很小,并且失去了好处- 来源
在少数情况下内联函数可能无法工作:
- 对于返回值的函数; 如果存在 return 语句。
- 对于不返回任何值的函数; 如果存在循环、switch 或 goto 语句。
- 如果函数是递归的。 -来源
__inline<仅当您指定优化选项时, /code> 关键字才会导致内联函数。 如果指定了优化,则是否遵循 __inline
取决于内联优化器选项的设置。 默认情况下,只要运行优化器,内联选项就会生效。 如果指定 optimize ,并且希望忽略__inline
关键字,则还必须指定 noinline 选项。 -来源
While it would be very convenient to use inline functions at some situations,
Are there any drawbacks with inline functions?
Conclusion:
Apparently, There is nothing wrong with using inline functions.
But it is worth noting the following points!
Overuse of inlining can actually make programs slower. Depending on a function's size, inlining it can cause the code size to increase or decrease. Inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. On modern processors smaller code usually runs faster due to better use of the instruction cache. - Google Guidelines
The speed benefits of inline functions tend to diminish as the function grows in size. At some point the overhead of the function call becomes small compared to the execution of the function body, and the benefit is lost - Source
There are few situations where an inline function may not work:
- For a function returning values; if a return statement exists.
- For a function not returning any values; if a loop, switch or goto statement exists.
- If a function is recursive. -Source
The
__inline
keyword causes a function to be inlined only if you specify the optimize option. If optimize is specified, whether or not__inline
is honored depends on the setting of the inline optimizer option. By default, the inline option is in effect whenever the optimizer is run. If you specify optimize , you must also specify the noinline option if you want the__inline
keyword to be ignored. -Source
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
正如其他人提到的, inline 关键字只是对编译器的提示。 事实上,大多数现代编译器会完全忽略这个提示。 编译器有自己的启发式方法来决定是否内联函数,坦率地说,不需要您的建议,非常感谢。
如果您真的非常想要内联某些内容,如果您实际上对其进行了分析并查看了反汇编以确保覆盖编译器启发式实际上有意义,那么这是可能的:
然而,inline 关键字确实有第二个有效的目的 - 在头文件中声明函数,而不是在类定义中声明函数。 需要 inline 关键字来告诉编译器不要生成函数的多个定义。
As others have mentioned, the inline keyword is only a hint to the compiler. In actual fact, most modern compilers will completely ignore this hint. The compiler has its own heuristics to decide whether to inline a function, and quite frankly doesn't want your advice, thank you very much.
If you really, really want to make something inline, if you've actually profiled it and looked at the disassembly to ensure that overriding the compiler heuristic actually makes sense, then it is possible:
The inline keyword does have a second, valid purpose however - declaring functions in header files but not inside a class definition. The inline keyword is needed to tell the compiler not to generate multiple definitions of the function.
我对此表示怀疑。 甚至编译器也会自动内联一些函数以进行优化。
I doubt it. Even the compiler automatically inlines some functions for optimization.
我不知道我的答案是否与问题相关,但是:
对于内联虚拟方法要非常小心! 一些有缺陷的编译器(例如 Visual C++ 的早期版本)会为虚拟方法生成内联代码,其中标准行为是不执行任何操作,而是沿着继承树向下调用适当的方法。
I don't know if my answer's related to the question but:
Be very careful about inline virtual methods! Some buggy compilers (previous versions of Visual C++ for example) would generate inline code for virtual methods where the standard behaviour was to do nothing but go down the inheritance tree and call the appropriate method.
您还应该注意,inline 关键字只是一个请求。 编译器可能会选择不内联它,同样,如果编译器认为速度/大小权衡值得,则编译器可能会选择将您未定义为内联的函数内联。
这个决定通常是基于很多因素做出的,例如速度优化(避免函数调用)和大小优化(内联可能导致代码膨胀,因此对于大型重复使用的函数来说不太好)之间的设置。
使用 VC++ 编译器,您可以使用 __forceinline 来推翻这个决定,
一般来说:
如果您确实想在标头中包含一个函数,请使用内联,但在其他地方没有什么意义,因为如果您想从中获得任何东西,一个好的编译器无论如何都会为您使其内联。
You should also note that the inline keyword is only a request. The compiler may choose not to inline it, likewise the compiler may choose to make a function inline that you did not define as inline if it thinks the speed/size tradeoff is worth it.
This decision is generaly made based on a number of things, such as the setting between optimise for speed(avoids the function call) and optimise for size (inlining can cause code bloat, so isn't great for large repeatedly used functions).
with the VC++ compiler you can overide this decision by using
__forceinline
SO in general:
Use inline if you really want to have a function in a header, but elsewhere theres little point because if your going to gain anything from it, a good compiler will be making it inline for you anyway.
内联较大的函数可以使程序变得更大,从而产生更多的指令缓存 错过并使其变慢。
决定函数何时足够小以进行内联会提高性能是相当棘手的。 Google 的 C++ 风格指南建议仅使用 10 行或较少的。
(简化)示例:
想象一个简单的程序,仅调用函数“X”5 次。
如果 X 很小并且所有调用都是内联的:可能所有指令都将通过一次主内存访问预取到指令缓存中 - 太棒了!
如果 X 很大,假设接近指令缓存的容量:
内联 X 可能会导致为 X 的每个内联实例从内存中获取一次指令。
如果 X 未内联,则可能会在第一次调用 X 时从内存中获取指令,但可能会保留在缓存中以供后续调用。
Inlining larger functions can make the program larger, resulting in more instruction cache misses and making it slower.
Deciding when a function is small enough that inlining will increase performance is quite tricky. Google's C++ Style Guide recommends only inlining functions of 10 lines or less.
(Simplified) Example:
Imagine a simple program that just calls function "X" 5 times.
If X is small and all calls are inlined: Potentially all instructions will be prefetched into the instruction cache with a single main memory access - great!
If X is large, let's say approaching the capacity of the instruction cache:
Inlining X will potentially result in fetching instructions from memory once for each inline instance of X.
If X isn't inlined, instructions may be fetched from memory on the first call to X, but could potentially remain in the cache for subsequent calls.
函数的过多内联会增加编译后的可执行文件的大小,这可能会对缓存性能产生负面影响,但现在编译器自行决定函数内联(取决于许多标准)并忽略 inline 关键字。
Excessive inlining of functions can increase size of compiled executable which can have negative impact on cache performance, but nowadays compiler decide about function inlining on their own (depending on many criterias) and ignore inline keyword.
在内联函数的其他问题中,我发现这些问题被严重过度使用(我见过 500 行的内联函数),您必须注意的是:
构建不稳定
#include
泄漏到客户端。 如果您重新设计内联函数并删除某些客户端依赖的不再使用的标头,这可能会非常令人讨厌。可执行文件大小
执行时间
我工作的编码标准将内联函数限制为简单的 setter/getter,并特别指出析构函数不应该是内联的,除非您有性能测量来显示内联带来了明显的优势。
Among other issues with inline functions, which I've seen heavily overused (I've seen inline functions of 500 lines), what you have to be aware of are:
build instability
#include
s leak into the client. This can be very nasty if you rework an inlined function and remove a no-longer used header which some client has relied on.executable size
execution time
The coding standard where I work limit inline functions to simple setters/getters, and specifically say destructors should not be inline, unless you have performance measurements to show the inlining confers a noticeable advantage.
除了其他很好的答案之外,至少有一次我看到强制内联实际上使受影响的代码减慢了 1.5 倍的情况。 里面有一个嵌套循环(相当小的一个),当这个函数被编译为一个单独的单元时,编译器设法有效地展开和优化它。 但是,当相同的函数被内联到更大的外部函数中时,编译器(MSVC 2017)无法优化此循环。
In addition to other great answers, at least once I saw a case where forced inlining actually slowed down the affected code by 1.5x. There was a nested loop inside (pretty small one) and when this function was compiled as a separate unit, compiler managed to efficiently unroll and optimize it. But when same function was inlined into much bigger outer function, compiler (MSVC 2017) failed to optimize this loop.
正如其他人所说,如果代码很大,内联函数会产生问题。由于每条指令都存储在特定的内存位置,因此内联函数的重载会使代码需要更多时间才能执行。
在其他情况下,内联可能不起作用
As other people said that inline function can create a problem if the the code is large.As each instruction is stored in a specific memory location ,so overloading of inline function make a code to take more time to get exicuted.
there are few other situations where inline may not work
值得指出的是,inline关键字实际上只是对编译器的一个提示。 编译器可能会忽略内联并简单地在某处生成该函数的代码。
内联函数的主要缺点是它会增加可执行文件的大小(取决于实例化的数量)。 在某些平台(例如嵌入式系统)上这可能是一个问题,特别是如果函数本身是递归的。
我还建议使内联函数非常小 - 内联函数的速度优势往往会随着函数大小的增大而减弱。 在某些时候,与函数体的执行相比,函数调用的开销变得很小,并且失去了好处。
It worth pointing out that the inline keyword is actually just a hint to the compiler. The compiler may ignore the inline and simply generate code for the function someplace.
The main drawback to inline functions is that it can increase the size of your executable (depending on the number of instantiations). This can be a problem on some platforms (eg. embedded systems), especially if the function itself is recursive.
I'd also recommend making inline'd functions very small - The speed benefits of inline functions tend to diminish as the function grows in size. At some point the overhead of the function call becomes small compared to the execution of the function body, and the benefit is lost.
它可以增加尺寸
可执行,而且我不认为
编译器实际上总是会做出
即使您使用了它们内联
内联关键字。 (或者是另一个
周围,就像Vaibhav
说?...)
我认为如果
函数只有 1 或 2 条语句。
编辑:这是 linux CodingStyle 文档对此的说明:
It could increase the size of the
executable, and I don't think
compilers will always actually make
them inline even though you used the
inline keyword. (Or is it the other
way around, like what Vaibhav
said?...)
I think it's usually OK if the
function has only 1 or 2 statements.
Edit: Here's what the linux CodingStyle document says about it:
内联存在一个问题 - 一旦您在头文件中定义了一个函数(这意味着通过在类内部定义成员函数的主体来显式或隐式地内联),就没有简单的方法可以在不强制用户重新编译的情况下更改它(与重新链接相对)。 这通常会导致问题,特别是当相关函数是在库中定义并且头文件是其接口的一部分时。
There is a problem with inline - once you defined a function in a header file (which implies inline, either explicit or implicit by defining a body of a member function inside class) there is no simple way to change it without forcing your users to recompile (as opposed to relink). Often this causes problems, especially if the function in question is defined in a library and header is part of its interface.
我同意其他帖子:
第三点是它可能会迫使您在标头中公开实现细节,例如,
如果没有内联,则 OtherObject 的前向声明是所有你需要的。 随着内联你的
header 需要OtherObject 的定义。
I agree with the other posts:
A third point is it may force you to expose implementation details in your headers, .e.g.,
Without the inline a forward declaration of OtherObject was all you needed. With the inline your
header needs the definition for OtherObject.