12

我知道您可以使用 inline 关键字,或者只是将一个方法放在类声明中,比如短 ctor 或 getter 方法,但是编译器是否会最终决定何时内联我的方法?

例如:

inline void Foo::vLongBar()
{
   //several function calls and lines of code
}

如果编译器认为它会使我的代码效率低下,它会忽略我的内联声明吗?

作为一个附带问题,如果我在我的类之外声明了一个 getter 方法,如下所示:

void Foo::bar() { std::cout << "baz"; }

编译器会在幕后内联吗?

4

9 回答 9

15

是的,是否内联代码的最终决定权在于 C++ 编译器。inline 关键字是一个建议,而不是要求。

以下是有关如何在 Microsoft C++ 编译器中处理此决定的一些详细信息

于 2009-07-30T07:30:24.370 回答
12

归根结底,函数是否内联完全取决于编译器。通常,函数在流程方面越复杂,编译器内联它的可能性就越小。并且某些函数,例如递归函数,根本无法内联。

不内联函数的主要原因是它会大大增加代码的整体大小,从而防止 iot 被保存在处理器的缓存中。这实际上是一种悲观主义,而不是一种优化。

至于让程序员决定在脚上或其他地方开枪,您可以自己内联函数 - 在函数的调用站点编写本应进入函数的代码。

于 2009-07-30T07:30:43.150 回答
4

正如许多人已经发布的那样,最终决定始终取决于编译器,即使您可以给出诸如 forceinline 之类的坚定提示。
部分理由是内联不是自动“更快”切换。过多的内联会使您的代码变得更大,并且可能会干扰其他优化。有关内联函数和性能,请参阅C++ FAQ Lite

于 2009-07-30T07:49:43.097 回答
4

正如其他人所指出的,该inline关键字只是对编译器内联代码的建议。由于编译器通常会内联未标记的代码,而不是内联代码,因此关键字似乎与or (pre-C++0x)inline一样冗余。registerauto

inline但是,关键字还影响了另一件事:它将函数的链接external(函数的默认值)更改为inline。内联链接允许每个编译单元包含它自己的目标代码副本,并让链接器从最终的可执行文件中删除冗余副本。如果这让您想起模板,是的,模板也使用内联链接。

于 2009-07-30T08:53:21.813 回答
3

是的,编译器拥有最终决定权。在 VS 中,您甚至可以将递归函数内联到指定的深度;)

#pragma inline_depth( [0... 255] )
于 2009-07-30T07:37:40.127 回答
3

只需添加我的 5 美分...

我发现这篇关于内联的 Guru of Week文章非常有用。

据我记得,我在某处读到,即使链接器也可能会进行内联,当它链接目标文件并发现被链接的代码可以内联时。

于 2009-07-30T14:31:16.980 回答
2

作为一个附带问题,如果我在我的类之外声明了一个 getter 方法,如下所示:

void Foo::bar() { std::cout << "baz"; }

编译器会在幕后内联吗?

这取决于。它可以用于同一翻译单元(.cpp文件及其所有#included 定义)中的所有调用者。但它仍然必须编译非内联版本,因为在翻译单元之外可能有该函数的调用者。您可能会在高优化级别上看到这一点(如果您的编译器确实可以做到的话)。(特别是:比较将所有 .cpp 文件#include 到一个 .cpp 与典型布局时发生的情况。在一个翻译单元中使用所有定义,这种内联的机会显着增加。)

于 2009-07-30T07:53:39.890 回答
1

据我所知,如果编译器发现 for、while 等循环,编译器会自动将您声明为内联(或在类声明中编写)的函数设为非内联。这是编译器在内联函数中拥有最后发言权的一个示例。

于 2009-07-30T07:31:22.213 回答
1

如果你真的,肯定,绝对,没有失败需要内联代码,总是有宏。C 多年来一直支持这些,因为它们只是在编译之前的文本替换,它们真的,真的,内联你写的任何东西。

这就是为什么 'inline' 关键字(甚至在某些情况下是强制变体)可以承受没有强制它的标准方式的原因——你总是可以只写一个宏。

也就是说,inline 关键字通常更好,因为编译器通常知道使函数内联是否有意义,并且内联可以与编译器的其余优化交互。

于 2009-07-30T14:38:15.830 回答