我知道内联是对编译器的提示或请求,用于避免函数调用开销。
我通常遵循一个拇指规则,我用3-4个简单的语句作为内联函数。但最好记住,这只是给编译器的一个提示。最终是否使它内联的调用仅由编译器执行。如果有超过这些语句,我不会用一个愚蠢的编译器进行内联声明,这可能会导致代码膨胀。
内联函数可能通过消除将参数推入堆栈的需要来提高代码性能。 如果有问题的函数是你代码的关键部分,你应该在你的项目的优化部分做出内联而不是内联的决定,
你可以在c++常见问题解答中阅读更多关于内联的内容
告诉编译器内联函数是一种优化,而最重要的优化规则是过早的优化是万恶之源。始终写清晰的代码(使用高效的算法),然后分析你的程序,只优化那些花费太长时间的函数。
如果您发现一个特定的函数非常简短,并且在一个紧凑的内部循环中被调用了数万次,那么它可能是一个很好的候选者。
不过,您可能会感到惊讶——许多c++编译器会自动为您内联小函数——而且它们可能也会忽略您的内联请求。
最好的方法是分析你的程序,并将被多次调用并消耗CPU周期的小函数标记为inline。这里的关键字是“小”——一旦函数调用开销与函数中花费的时间相比可以忽略不计,那么内联它们就没有意义了。
inline
我建议的另一种用法是,如果你有一些小函数在性能关键代码中经常被调用,以至于缓存不相关,你可能也应该内联这些函数。同样,这也是侧写师应该能够告诉你的。
最好的方法是检查和比较生成的内联和非内联指令。然而,省略inline总是安全的。使用inline可能会导致你不想要的麻烦。
避免函数调用的开销只是故事的一半。
做的事:
#define
别:
在开发一个库的时候,为了让一个类将来可以扩展,你应该:
记住,inline关键字是对编译器的一个提示:编译器可能决定不内联某个函数,也可能决定内联那些一开始就没有标记为inline的函数。我通常避免标记函数inline(可能在编写非常非常小的函数时分开)。
关于性能,明智的方法是(一如既往)分析应用程序,然后最终inline一组表示瓶颈的函数。
引用:
编辑:Bjarne Stroustrup, c++编程语言:
函数可以定义为inline。例如:
inline int fac(int n) { return (n < 2) ? 1 : n * fac(n-1); }
inline说明符是对编译器的一个提示,它应该尝试内联生成fac()调用的代码,而不是一次性为函数设置代码,然后通过通常的函数调用机制进行调用。聪明的编译器可以为调用fac(6)生成常量720。相互递归的内联函数、递归或不依赖于输入的内联函数的可能性,使得不可能保证inline函数的每次调用实际上都是内联的。编译器的聪明程度是无法规定的,所以一个编译器可能生成720,另一个生成6 * fac(5),还有一个生成非内联调用fac(6)。 为了在没有特别聪明的编译和链接工具的情况下实现内联,内联函数的定义(而不仅仅是声明)必须在作用域内(§9.2)。inline表示符不影响函数的语义。特别是,内联函数仍然有唯一的地址,因此内联函数的static变量(§7.1.2)也有唯一的地址。
inline说明符是对编译器的一个提示,它应该尝试内联生成fac()调用的代码,而不是一次性为函数设置代码,然后通过通常的函数调用机制进行调用。聪明的编译器可以为调用fac(6)生成常量720。相互递归的内联函数、递归或不依赖于输入的内联函数的可能性,使得不可能保证inline函数的每次调用实际上都是内联的。编译器的聪明程度是无法规定的,所以一个编译器可能生成720,另一个生成6 * fac(5),还有一个生成非内联调用fac(6)。
fac()
fac(6)
720
6 * fac(5)
为了在没有特别聪明的编译和链接工具的情况下实现内联,内联函数的定义(而不仅仅是声明)必须在作用域内(§9.2)。inline表示符不影响函数的语义。特别是,内联函数仍然有唯一的地址,因此内联函数的static变量(§7.1.2)也有唯一的地址。
static
EDIT2: ISO-IEC 14882-1998, 7.1.2功能说明
带有inline说明符的函数声明(8.3.5,9.3,11.4)声明了一个内联函数。内联说明符向实现指示,在调用点对函数体进行内联替换将优先于通常的函数调用机制。实现不需要在调用点执行这种内联替换;然而,即使省略了这个内联替换,7.1.2中定义的内联函数的其他规则仍应遵守。
过早的优化是万恶之源!
根据经验,我通常只内联“getter”和“setter”。一旦代码可以工作并且稳定,分析就可以显示哪些函数可以从内联中受益。
另一方面,大多数现代编译器都有很好的优化算法,并且会内联您应该内联的内容。
推理——编写内联单行函数,以后再考虑其他函数。
在决定是否使用内联时,我通常记住以下想法:在现代机器上,内存延迟可能是比原始计算更大的瓶颈。众所周知,经常调用的内联函数会增加可执行文件的大小。此外,这样的函数可以存储在CPU的代码缓存中,当需要访问代码时,这将减少缓存失败的数量。
因此,您必须自己决定:内联是否会增加或减少生成的机器代码的大小?调用该函数会导致缓存丢失的可能性有多大?如果它遍布整个代码,那么我认为可能性很高。如果它被限制在一个单一的紧密循环,那么可能性很低。
我通常使用内联的情况下,我列出如下。然而,当您真正关心性能时,概要分析是必不可少的。此外,您可能希望检查编译器是否真的接受了提示。
我经常使用内联函数不是为了优化,而是为了使代码更具可读性。有时代码本身比注释、描述性名称等更短、更容易理解。例如:
void IncreaseCount() { freeInstancesCnt++; }
读者可以立即了解代码的完整语义。
inline与优化几乎没有关系。inline是对编译器的指令,如果给定的函数定义在程序中多次出现,则不会产生错误,并承诺该定义将在使用它的每次翻译中出现,并且在它出现的任何地方都具有完全相同的定义。
根据上述规则,inline适用于短函数,其函数体不需要包含超出声明所需的额外依赖项。每次遇到定义时,都必须对其进行解析,并可能生成其主体的代码,因此对于在单个源文件中只定义一次的函数,这意味着一些编译器开销。
编译器可以内联(即用执行该函数的操作的代码替换对该函数的调用)它选择的任何函数调用。过去的情况是,它“显然”不能内联一个没有在同一个翻译单元中声明的函数,但随着链接时间优化的使用越来越多,现在这种情况也不存在了。同样正确的事实是,标记为inline的函数可能不能内联。
此外,在维护大型项目时,内联方法有严重的副作用。当内联代码被更改时,所有使用它的文件将由编译器自动重建(如果它是一个好的编译器)。这可能会浪费大量的开发时间。
当inline方法被转移到源文件并且不再内联时,整个项目必须重新构建(至少这是我的经验)。当方法转换为内联时也是如此。
我读了一些答案,发现有些东西缺失了。
我使用的规则是不使用内联,除非我希望它是内联的。看起来很傻,现在解释一下。
编译器足够聪明,短函数总是内联的。永远不要让长函数作为内联函数,除非程序员说这样做。
我知道内联是一个提示或请求编译器
实际上inline是编译器的顺序,它没有选择,并且在inline关键字之后使所有代码内联。所以你永远不能使用inline关键字,编译器将设计最短的代码。
那么什么时候使用inline呢?
如果您想内联一些代码,则使用。我只知道一个例子,因为我只在一种情况下使用它。即用户认证。
例如,我有这样一个函数:
inline bool ValidUser(const std::string& username, const std::string& password) { //here it is quite long function }
不管这个函数有多大,我都想把它作为内联的,因为它使我的软件更难破解。
只有当函数代码很小时,才应该使用内联函数限定符。如果函数比较大,则应该使用普通函数,因为节省内存空间可以换取相对较小的执行速度牺牲。