何时使用内联函数,何时不使用它?

9 浏览
0 Comments

何时使用内联函数,何时不使用它?

我知道inline是给编译器的一种提示或请求,用于避免函数调用的开销。

那么,有什么依据可以确定一个函数是否适合进行内联?

在什么情况下应该避免内联?

0
0 Comments

在什么情况下使用内联函数以及在什么情况下不使用内联函数?这个问题的出现的原因是人们对于内联函数的作用和效果存在一定的疑惑。解决方法是先编写清晰的代码,使用高效的算法,然后对程序进行性能分析,只对执行时间过长的函数进行优化。

内联函数是一种优化方法,而优化的最重要原则是不要过早进行优化。因此,首先需要编写清晰的代码和高效的算法,然后通过性能分析确定哪些函数需要进行优化。

当一个函数非常简短且简单,并且在一个紧密的内部循环中被调用数万次时,它可能是一个很好的候选函数。

然而,许多C++编译器会自动为你进行函数内联的优化,它们可能会忽略你对内联的请求。

实际上,我怀疑某些编译器会完全忽略"inline"关键字,只会响应"__inline"或"__force_inline"。我想这是为了防止滥用。

通常情况下,并非如此。内联只是一个提示,但大多数编译器都会认真对待它。你可以设置编译器在生成目标代码时同时生成汇编代码(在Visual Studio中使用"/FAcs",在GCC中使用"-s"),以查看它的具体行为。根据我的经验,这两个编译器都非常重视内联关键字。

有趣的是,根据我的经验,无论是g++还是VC编译器都不会对"inline"关键字进行内联。也就是说,如果你看到函数被内联了,并且将"inline"修饰符从函数中删除,它仍然会被内联。如果你有任何相反的具体例子,请分享给我!

我更多是指相反的情况:编译器可以自由地内联任何它喜欢的函数,但很少见到它选择不内联我告诉它要内联的函数。我通常在这里使用的是get/set函数(我在.h中进行内联而不是在.cpp中定义)和3D向量操作。由于某种原因,像点乘/叉乘、正交化等函数似乎刚好处于MSVC不会自动内联它们的边缘,但会遵守"inline"关键字。

我可能是错误的,我确信我曾经在其中一个标准头文件中看到过“#define inline”,但这可能只是一些用于C的向后兼容性标志。另外,编译器可以内联任何它选择的函数。

为什么"inline"关键字会阻碍"清晰代码"?引用中的"premature optimization"关键字是"premature",而不是"optimization"。说你应该积极地避免优化只是无稽之谈。这句话的意思是你应该避免那些可能不必要并对代码有害副作用的优化(例如使代码难以维护)。我不明白为什么"inline"关键字会让代码难以维护,或者为什么将其添加到函数中会有害。

有时候内联函数会使代码变慢,而不是变快。一个例子是当函数从代码的多个不同位置调用时;如果函数没有被内联,那么当它从不同的位置调用时,它可能仍然存在于指令缓存中,分支预测器可能已经预热好了。有一些模式总是能提高效率,因此使用它们永远不会有坏处。内联不是其中之一。它通常对性能没有影响,有时会有帮助,有时会有害。我坚持我的建议:先进行性能分析,然后再进行内联。

在正确的情况下,内联有时会带来巨大的性能提升。我进行过测量:assemblyrequired.crashworks.org/2009/01/19/...

0
0 Comments

内联函数与优化几乎没有什么关系。内联是一条指令,告诉编译器如果给定的函数定义在程序中出现多次时不要产生错误,并承诺在使用的每个翻译和出现的地方都会有相同的定义。

根据上述规则,内联适用于函数体不需要包含额外依赖项的短函数。每次遇到定义时,都需要解析它并可能生成其代码,因此与在单个源文件中仅定义一次的函数相比,它会给编译器带来一些额外开销。

编译器可以选择内联(即用执行该函数操作的代码替换函数调用)。过去,一个函数如果在调用的同一翻译单元中没有声明,显然是无法内联的,但随着链接时优化的增加,这个说法不再正确。同样真实的是,标记为内联的函数可能不会被内联。

我觉得这更像是C++中的一个偶然巧合,而不是一个有意的功能。这个想法与C中的“静态”全局变量非常相似。这是一个非常有趣的答案。不过,我希望他们能使用像“internal”这样的关键字来表示内部链接。

+1. : 我真的不确定你在说什么。链接与内联关键字有什么关系?什么是偶然巧合?

: 回顾我的评论,我意识到它相当模糊,没有经过深思熟虑。在多个文件中定义相同的函数会导致链接器错误,可以通过将函数声明为“static”来解决这个问题。然而,“inline”允许您以细微的差别做同样的事情,它们实际上没有像“static”那样的内部链接。我怀疑这实际上更像是一个巧合,因为语言实现者/设计者意识到他们需要对在头文件中声明的函数进行特殊处理,而这个特性也延续到了“inline”上。

不知道为什么你的评论获得了这么多赞,因为性能是使用内联的主要原因。

“过早优化是万恶之源”,如果你关心性能,只需将-O3添加到编译器标志中,编译器将自动确定要内联的内容。不要添加关键字并期望它们使您的代码更快。我听过一堂关于优化的讲座,讲师在LLVM工作,他说内联关键字与优化几乎没有什么关系,它只是与语义/语言规则有关。

0
0 Comments

在使用内联函数和不使用内联函数时避免函数调用的成本只是其中一部分。以下是一些使用内联函数和不使用内联函数的指导原则:

使用内联函数的情况:

- 使用`inline`关键字而不是`#define`

- 非常小的函数是内联的好候选对象:代码更快,可执行文件更小(更有机会保留在代码缓存中)

- 函数很小且被频繁调用

不使用内联函数的情况:

- 大型函数:导致更大的可执行文件,这会显著影响性能,而不管调用开销是否更快

- I/O绑定的内联函数

- 函数很少被使用

- 构造函数和析构函数:即使是空的,编译器也会生成代码

- 当开发库时破坏二进制兼容性:

- 内联现有函数

- 更改内联函数或使内联函数非内联:库的旧版本调用旧的实现

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

- 添加非内联虚析构函数,即使函数体为空

- 将所有构造函数设置为非内联

- 除非类不能通过值进行复制,否则编写非内联实现的复制构造函数和赋值运算符的函数

记住,`inline`关键字只是对编译器的提示:编译器可以决定不内联函数,并且可以决定内联未标记为`inline`的函数。通常情况下,我避免将函数标记为`inline`(除非写非常非常小的函数)。对于性能,明智的方法是(一如既往地)对应用程序进行分析,然后最终将一组表示瓶颈的函数标记为`inline`。

参考资料:

- To Inline or Not To Inline

- Inline functions

- Policies/Binary Compatibility Issues With C++

- GotW #33: Inline

- Inline Redux

- Effective C++ - Item 33: Use inlining judiciously

当需要解决二义性问题时,可以查阅《The C++ Programming Language》和ISO-IEC 14882-1998的相应章节。

避免函数调用成本只是解决问题的一半。这里所提到的问题是关于何时使用内联函数和何时不使用内联函数的问题。这个问题的答案是根据函数的特性和需求来决定的。需要注意的是,内联函数并不是一定会被内联的,而且非内联函数也有可能被内联。因此,在使用内联函数时,需要根据实际情况进行性能分析和测试,然后决定是否将函数标记为内联。

0