C++ 何时使用内联函数,何时不使用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1932311/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:37:53  来源:igfitidea点击:

When to use inline function and when not to use it?

c++cinline

提问by Ashish

I know that inline is a hint or request to compiler and its used to avoid function call overheads.

我知道内联是对编译器的提示或请求,它用于避免函数调用开销。

So on what basis one can determine whether a function is a candidate for inlining or not ? In which case one should avoid inlining ?

那么基于什么可以确定一个函数是否适合内联呢?在哪种情况下应该避免内联?

回答by Gregory Pakosz

Avoiding the cost of a function call is only half the story.

避免函数调用的成本只是故事的一半。

do:

做:

  • use inlineinstead of #define
  • very smallfunctions are good candidates for inline: faster code and smaller executables (more chances to stay in the code cache)
  • the function is small andcalled very often
  • 使用inline代替#define
  • 非常小的函数非常适合inline:更快的代码和更小的可执行文件(更多的机会留在代码缓存中)
  • 该函数很小并且经常被调用

don't:

别:

  • large functions: leads to larger executables, which significantly impairs performance regardless of the faster execution that results from the calling overhead
  • inline functions that are I/O bound
  • the function is seldom used
  • constructors and destructors: even when empty, the compiler generates code for them
  • breaking binary compatibility when developing libraries:
    • inline an existing function
    • change an inline function or make an inline function non-inline: prior version of the library call the old implementation
  • 大型函数:导致更大的可执行文件,这会显着降低性能,而不管调用开销导致执行速度更快
  • I/O 绑定的内联函数
  • 该功能很少使用
  • 构造函数和析构函数:即使为空,编译器也会为它们生成代码
  • 开发库时破坏二进制兼容性:
    • 内联现有函数
    • 更改内联函数或使内联函数非内联:库的先前版本调用旧实现

when developing a library, in order to make a class extensible in the future you should:

在开发库时,为了使类在未来可扩展,您应该:

  • add non-inline virtual destructor even if the body is empty
  • make all constructors non-inline
  • write non-inline implementations of the copy constructor and assignment operator unless the class cannot be copied by value
  • 即使主体为空,也添加非内联虚拟析构函数
  • 使所有构造函数都非内联
  • 编写复制构造函数和赋值运算符的非内联实现,除非该类不能按值复制

Remember that the inlinekeyword is a hint to the compiler: the compiler may decide not to inline a function and it can decide to inline functions that were not marked inlinein the first place. I generally avoid marking function inline(apart maybe when writing very very small functions).

请记住,inline关键字是对编译器的一个提示:编译器可能决定不内联函数,并且可以决定内联最初未标记的函数inline。我通常避免标记函数inline(除了编写非常非常小的函数时)。

About performance, the wise approach is (as always) to profile the application, then eventually inlinea set of functions representing a bottleneck.

关于性能,明智的方法是(一如既往)分析应用程序,然后最终inline是一组代表瓶颈的函数。

References:

参考:



EDIT: Bjarne Stroustrup, The C++ Programming Language:

编辑:Bjarne Stroustrup,C++ 编程语言:

A function can be defined to be inline. For example:

一个函数可以定义为inline。例如:

inline int fac(int n)
{
  return (n < 2) ? 1 : n * fac(n-1);
}

The inlinespecifier is a hint to the compiler that it should attempt to generate code for a call of fac()inline rather than laying down the code for the function once and then calling through the usual function call mechanism. A clever compiler can generate the constant 720for a call fac(6). The possibility of mutually recursive inline functions, inline functions that recurse or not depending on input, etc., makes it impossible to guarantee that every call of an inlinefunction is actually inlined. The degree of cleverness of a compiler cannot be legislated, so one compiler might generate 720, another 6 * fac(5), and yet another an un-inlined call fac(6).

To make inlining possible in the absence of unusually clever compilation and linking facilities, the definition–and not just the declaration–of an inline function must be in scope (§9.2). An inlineespecifier does not affect the semantics of a function. In particular, an inline function still has a unique address and so has staticvariables (§7.1.2) of an inline function.

inline说明符的提示,编译器,它应该尝试为的呼叫生成代码fac()内联,而不是放下码一次函数,然后通过常规的函数调用机制调用。聪明的编译器可以720为调用生成常量fac(6)。内联函数相互递归的可能性,内联函数是否递归取决于输入等,使得无法保证inline函数的每次调用实际上都是内联的。编译器的聪明程度无法通过立法来确定,因此一个编译器可能会生成720、另一个6 * fac(5)和另一个未内联调用fac(6)

为了在没有异常聪明的编译和链接设施的情况下使内联成为可能,内联函数的定义——而不仅仅是声明——必须在范围内(第 9.2 节)。说明inline符不影响函数的语义。特别是,内联函数仍然具有唯一地址,因此具有static内联函数的变量(第 7.1.2 节)。

EDIT2: ISO-IEC 14882-1998, 7.1.2 Function specifiers

EDIT2: ISO-IEC 14882-1998, 7.1.2 功能说明符

A function declaration (8.3.5, 9.3, 11.4) with an inlinespecifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.

带有inline说明符的函数声明 (8.3.5, 9.3, 11.4)声明了一个内联函数。内联说明符向实现表明,在调用点函数体的内联替换优先于通常的函数调用机制。不需要实现在调用点执行此内联替换;然而,即使省略了这种内联替换,7.1.2 中定义的内联函数的其他规则仍应遵守。

回答by CB Bailey

inlinehas very little to do with optimization. inlineis an instruction to the compiler not to produce an error if the function given definition occurs multiple times in the program and a promise that the definition will occur in every translation that it is used and everywhere it does appear it will have exactly the same definition.

inline与优化关系不大。inline是对编译器的指令,如果给定的函数在程序中多次出现,则不会产生错误,并承诺该定义将出现在使用它的每个翻译中,并且在它出现的任何地方都将具有完全相同的定义。

Given the above rules, inlineis suitable for short functions whose body doesn't necessitate including extra dependencies over what just a declaration would need. Every time the defintion is encountered it must be parsed and code for its body may be generated so it implies some compiler overhead over a function defined only once in a single source file.

鉴于上述规则,inline适用于其主体不需要包含对声明所需内容的额外依赖的短函数。每次遇到定义时,都必须对其进行解析,并且可能会生成其主体的代码,因此这意味着对在单个源文件中仅定义一次的函数会产生一些编译器开销。

A compiler may inline(i.e. replace a call to the function with code that performs that action of that function) any function call that it chooses. It used to be the case that it "obviously" couldn't inline a function that wasn't declared in the same translation unit as the call but with the increasing use of link time optimization even this isn't true now. Equally true is the fact that functions marked inlinemay not be inlined.

编译器可以内联(即用执行该函数的该操作的代码替换对该函数的调用)它选择的任何函数调用。过去的情况是,它“显然”无法内联未在与调用相同的翻译单元中声明的函数,但随着链接时间优化的使用越来越多,即使现在不是这样。同样正确的事实是,标记的函数inline可能不会被内联。

回答by dmazzoni

Telling the compiler to inline a function is an optimization, and the most important rule of optimization is that premature optimization is the root of all evil. Always write clear code (using efficient algorithms), then profile your program and only optimize functions that are taking too long.

告诉编译器内联函数是一种优化,最重要的优化规则是过早优化是万恶之源。始终编​​写清晰的代码(使用有效的算法),然后分析您的程序并仅优化耗时过长的函数。

If you find a particular function is very short and simple, and it's getting called tens of thousands of times in a tight inner loop, it might be a good candidate.

如果您发现某个特定函数非常短小且简单,并且在紧密的内部循环中被调用了数万次,那么它可能是一个不错的选择。

You might be surprised, though - many C++ compilers will automatically inline small functions for you - and they might ignore your request to inline, too.

不过,您可能会感到惊讶 - 许多 C++ 编译器会自动为您内联小函数 - 他们也可能会忽略您的内联请求。

回答by Timo Geusch

The best way to find out is to profile your program and mark small functions that get called lots of times and burn through CPU cycles that as inline. The keyword here is "small" - once the function call overhead is negligible compared to the time spent in the function, it's pointless to inline them.

找出答案的最佳方法是分析您的程序并标记被多次调用并消耗 CPU 周期的小函数,如inline. 这里的关键字是“小”——一旦函数调用的开销与在函数中花费的时间相比可以忽略不计,内联它们就毫无意义了。

The other use I'd suggest is if you've got small functions that get called in performance critical code often enough to make a cache miss relevant, you should probably inline those as well. Again, it's something the profiler should be able to tell you.

我建议的另一个用途是,如果您有一些小函数在性能关键代码中被调用的频率足以使缓存未命中相关,那么您可能也应该内联这些函数。同样,这是分析器应该能够告诉您的。

回答by Kornel Kisielewicz

Premature optimization is the root of all evil!

过早优化是万恶之源!

As a rule of thumb I usually inline only "getters" and "setters". Once the code is working and is stable, profiling can show which functions could benefit from inlining.

根据经验,我通常只内联“getter”和“setter”。一旦代码运行并稳定,分析可以显示哪些函数可以从内联中受益。

On the other hand, most modern compilers have quite good optimization algorithms, and will inline what you should have inlined for you.

另一方面,大多数现代编译器都有很好的优化算法,并且会内联您应该为您内联的内容。

Reasuming -- write inline one-liner functions, and worry about others later.

Reasuming——写内联的单行函数,以后再担心其他的。

回答by Alon

Inline functions mightimprove your code performance by eliminating the need to push arguments into the stack. if the function in question is in a critical part of your code you should make the inline not inline decision in the optimization part of your project,

通过消除将参数推入堆栈的需要,内联函数可能会提高您的代码性能。如果有问题的函数在您代码的关键部分,您应该在项目的优化部分做出内联而不是内联的决定,

you can read more about inlines in the c++ faq

您可以在c++ 常见问题解答中阅读有关内联的更多信息

回答by danatel

I often use inline functions not as an optimization but to make the code more readable. Sometimes the code itself is shorter and easier to understand than comments, descriptive names etc. For example:

我经常使用内联函数不是为了优化,而是为了使代码更具可读性。有时代码本身比注释、描述性名称等更短且更容易理解。例如:

void IncreaseCount() { freeInstancesCnt++; }

The reader immediately knows the complete semantics of the code.

读者立即知道代码的完整语义。

回答by Rehno Lindeque

When deciding on whether to use inline, I usually keep the following idea in mind: On modern machines memory latency can be a bigger bottleneck than raw calculations. Inlining functions that are called often is known to grow the executable size. Furthermore, such a function could be stored in the CPU's code cache which will decrease the number of cache misses when that code needs to be accessed.

在决定是否使用内联时,我通常牢记以下想法:在现代机器上,内存延迟可能是比原始计算更大的瓶颈。众所周知,经常调用的内联函数会增加可执行文件的大小。此外,这样的函数可以存储在 CPU 的代码缓存中,当需要访问该代码时,这将减少缓存未命中的次数。

Hence, you have to decide for yourself: Does inlining increase or decrease the size of the generated machine code? How likely is it that calling the function will cause a cache miss? If it is peppered throughout the code, then I would say the likelihood is high. If it is restricted to a single tight loop then the likelihood is hopefully low.

因此,您必须自己决定:内联是增加还是减少生成的机器代码的大小?调用该函数导致缓存未命中的可能性有多大?如果它贯穿整个代码,那么我会说可能性很高。如果它仅限于单个紧密循环,则可能性很小。

I typically use inlining in the cases I list bellow. However, where you are genuinely concerned about performance, profiling is essential. Furthermore, you might want to check whether the compiler actually takes the hint.

我通常在下面列出的情况下使用内联。然而,当您真正关心性能时,分析是必不可少的。此外,您可能想要检查编译器是否真的接受了提示。

  • Short routines that are called in a tight loop.
  • Very basic accessors (get / set) and wrapper functions.
  • Template code in header files unfortunately automatically obtain the inline hint.
  • Short code that is used like a macro. (E.g. min() / max())
  • Short math routines.
  • 在紧密循环中调用的短例程。
  • 非常基本的访问器(get/set)和包装函数。
  • 不幸的是,头文件中的模板代码会自动获取内联提示。
  • 像宏一样使用的短代码。(例如 min() / max())
  • 简短的数学例程。

回答by wallyk

The best way would be to examine and compare the generated instructions for inlined and not inlined. However, it is always safe to omit inline. Using inlinecould lead to trouble you don't want.

最好的方法是检查和比较生成的内联和非内联指令。但是,省略 总是安全的inline。使用inline可能会导致您不想要的麻烦。

回答by Naveen

I generally follow a thumb rule where I make a function with 3-4 simple statements as inline. But it is good to remember that it is just a hint to the compiler. The final call to make it inline or not is taken by the compiler only. If there are more than these many statements I will not declare inline as with a stupid compiler it may lead to code bloat.

我通常遵循一个拇指规则,我使用 3-4 个简单语句作为内联函数创建一个函数。但最好记住它只是对编译器的一个提示。使其内联与否的最终调用仅由编译器执行。如果语句多于这些,我不会像愚蠢的编译器那样声明内联,这可能会导致代码膨胀。