还有内联使用吗? [英] Is there still a use for inline?

查看:117
本文介绍了还有内联使用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我相信, inline 已过时,因为我阅读了这里< a>:


无论如何将函数指定为 inline 允许编译器忽略的请求:编译器可能内联展开一些,全部或没有调用指定为 inline 的函数的地方。


但是, Angew 似乎理解我不喜欢。在这个问题,他和我来回走了很多,是否 inline 这个问题是 问题:





请记住编译器可以随意 inline ,因此 inline 在此方面没有帮助: inline 可以用于强制,不建议

解决方案

我会尝试以最好的方式解释我的秘密理解。



这里有两个完全独立的概念。一个是编译器通过在调用点直接重复函数体来替换函数调用的能力。另一种是在多个翻译单元(=多于 .cpp 文件)中定义函数的可能性。



第一个称为函数内联。第二个是 inline 关键字的目的。 inline 关键字对于编译器也是一个强烈建议,它应该内联标记 inline 。随着编译器在优化时变得更好,这个功能已经退化了,并且使用 inline 作为内联函数的建议确实是过时的。如果它发现这是一个更好的优化,编译器会很高兴地忽略它和内联的东西。



我希望我们处理显式 inline –内联关系。



那么, inline 关键字的实际用途是什么?很简单:标记为 inline 的函数可以在不违反单一定义规则(ODR)的情况下在多个翻译单元中定义。想象这两个文件:



file1.cpp

  int f(){return 42; } 

int main()
{return f(); }

file2.cpp

  int f(){return 42; } 

此命令:

 > gcc file1.cpp file2.cpp 

会产生一个链接器错误,抱怨符号<$ c $



但是,如果你用 inline 关键字,它具体告诉编译器&链接器:你们确保这个函数的多个相同的定义不会导致任何错误!





file1.cpp

  int f(){return 42; } 

int main()
{return f(); }

file2.cpp

  inline int f(){return 42; } 

将这两个文件编译并链接在一起不会产生任何链接器错误。



注意,当然, f 的定义并不一定要在文件中。它可以来自 #include d头文件:



f.hpp

  inline int f(){return 42; } 

file1.cpp

  #includef.hpp

int main()
{return f(); }

file2.cpp

  #includef.hpp

基本上,为了能够将函数定义写入头文件,必须将其标记为 inline ,否则会导致多个定义错误。






最后一个谜题是:为什么关键字拼写 inline 它与内联无关?原因很简单:为了内联一个函数(即,通过在调用点重复它的主体来替换它的调用),编译器必须首先具有该函数的主体。



C ++遵循单独的编译模型,其中编译器无法访问除当前生成的对象文件之外的对象文件。因此,为了能够内联函数,其定义必须是当前翻译单元的一部分。如果你想能够在多个翻译单元中嵌入它,它的定义必须在所有的翻译单元中。通常,这将导致多重定义错误。所以如果你把你的函数放在一个标题中,并且 #include 它的定义无处不在,使其内联无处不在,你必须标记为 inline 以防止多个定义错误。



请注意,即使今天,虽然编译器将内联任何函数是适合的,它必须仍然可以访问该函数的定义。因此,虽然 inline 关键字不需要作为提示请内联此,您仍然可能会发现您需要使用它来启用编译器做内联如果它选择这样做。没有它,你可能无法得到定义到翻译单元,并且没有定义,编译器根本不能内联函数。



编译器不能。链接器可以。现代优化技术包括链接时间代码生成(a.k.a. Whole Program Optimization),其中优化器在实际链接之前作为链接过程的一部分运行所有对象文件。在这一步中,所有的函数定义当然是可用的,并且内联是完全可能的,而没有在程序中的任何位置使用单个 inline 关键字。但是这种优化通常在构建时间上是昂贵的,特别是对于大型项目。考虑到这一点,仅仅依赖LTCG内联可能不是最好的选择。






为了完整性:欺骗在第一部分。 ODR属性实际上不是 inline 关键字的属性,而是内联函数(这是语言的一个术语)的属性。内联函数的规则是:




  • 可以在多个翻译单元中定义,而不会导致链接器错误


  • 所有的定义都必须是令牌令牌和实体相同



inline 关键字将函数转换为内联函数。将函数标记为内联的另一种方法是在类定义中直接定义(而不仅仅是声明)它。即使没有 inline 关键字,这样的函数也会自动内联。


I believed, inline was obsolete because I read here:

No matter how you designate a function as inline, it is a request that the compiler is allowed to ignore: the compiler might inline-expand some, all, or none of the places where you call a function designated as inline.

However, Angew seems to understand something I don't. In this question he and I go back and forth quite a bit, on whether inline is still useful.

This question is not a question on:

Bearing in mind that the compiler can inline at will, so inline is not helpful there: Where can inline be used to force, not suggest, a change in compiled code?

解决方案

I will try to explain my "secret understanding" the best way I can.

There are two entirely separate concepts here. One is the compiler's ability to replace a function call by repeating the function body directly at the call site. The other is the possibility of defining a function in more than one translation unit (= more than one .cpp file).

The first one is called function inlining. The second is the purpose of the inline keyword. Historically, the inline keyword was also a strong suggestion to the compiler that it should inline the function marked inline. As compilers became better at optimising, this functionality has receded, and using inline as a suggestion to inline a function is indeed obsolete. The compiler will happily ignore it and inline something else entirely if it finds that's a better optimisation.

I hope we've dealt with the explicit inline–inlining relationship. There is none in current code.

So, what is the actual purpose of the inline keyword? It's simple: a function marked inline can be defined in more than one translation unit without violating the One Definition Rule (ODR). Imagine these two files:

file1.cpp

int f() { return 42; }

int main()
{ return f(); }

file2.cpp

int f() { return 42; }

This command:

> gcc file1.cpp file2.cpp

Will produce a linker error, complaining that the symbol f is defined twice.

However, if you mark a function with the inline keyword, it specifically tells the compiler & linker: "You guys make sure that multiple identical definitions of this function do not result in any errors!"

So the following will work:

file1.cpp

inline int f() { return 42; }

int main()
{ return f(); }

file2.cpp

inline int f() { return 42; }

Compiling and linking these two files together will not produce any linker errors.

Notice that of course the definition of f doesn't have to be in the files verbatim. It can come from an #included header file instead:

f.hpp

inline int f() { return 42; }

file1.cpp

#include "f.hpp"

int main()
{ return f(); }

file2.cpp

#include "f.hpp"

Basically, to be able to write a function definition into a header file, you have to mark it as inline, otherwise it will lead to multiple definition errors.


The last piece of the puzzle is: why is the keyword actually spelled inline when it has nothing to do with inlining? The reason is simple: to inline a function (that is, to replace a call to it by repeating its body on the call site), the compiler must have the function's body in the first place.

C++ follows a separate compilation model, where the compiler doesn't have access to object files other than the one it's currently producing. Therefore, to be able to inline a function, its definition must be part of the current translation unit. If you want to be able to inline it in more than one translation unit, its definition has to be in all of them. Normally, this would lead to a multiple definition error. So if you put your function in a header and #include its definition everywhere to enable its inlining everywhere, you have to mark it as inline to prevent multiple definition errors.

Notice that even today, while a compiler will inline any function is sees fit, it must still have access to that function's definition. So while the inline keyword is not required as the hint "please inline this," you may still find you need to use it to enable the compiler to do the inlining if it chooses to do so. Without it, you might not be able to get the definition into the translation unit, and without the definition, the compiler simply cannot inline the function.

The compiler cannot. The linker can. Modern optimisation techniques include Link-Time Code Generation (a.k.a. Whole Program Optimisation), where the optimiser is run over all object files as part of the linking process, before the actual linking. In this step, all function definitions are of course available and inlining is perfectly possible without a single inline keyword being used anywhere in the program. But this optimisation is generally costly in build time, especially for large projects. With this in mind, relying solely on LTCG for inlining may not be the best option.


For completeness: I've cheated slightly in the first part. The ODR property is actually not a property of the inline keyword, but of inline functions (which is a term of the language). The rules for inline functions are:

  • Can be defined in multiple translation units without causing linker errors
  • Must be defined in every translation unit in which it is used
  • All its definitions must be token-for-token and entity-for-entity identical

The inline keyword turns a function into an inline function. Another way to mark a function as inline is to define (not just declare) it directly in a class definition. Such a function is inline automatically, even without the inline keyword.

这篇关于还有内联使用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆