我应该何时为函数/方法编写关键字'inline'?

Par*_*ial 526 c++ inline one-definition-rule

我应该何时inline在C++中为函数/方法编写关键字?

看到一些答案,一些相关的问题:

  • 我应该何时写在C++函数/方法关键字"内联"?

  • 什么时候编译器不知道何时使函数/方法'内联'?

  • 当一个应用程序为函数/方法写入"内联"时,是否多线程是否重要?

def*_*ode 822

哦,男人,我的一个宠儿小便.

inline更像是staticextern不是指令告诉编译器内联你的函数. extern,static,inline是联动指令,几乎完全是由连接器,而不是编译器使用.

据说,inline您认为函数应该内联到编译器的提示.这可能是在1998年,但十年后编译器不需要这样的提示.更不用说人类在优化代码时通常是错误的,因此大多数编译器都会忽略"提示".

  • static - 变量/函数名称不能用于其他翻译单元.链接器需要确保它不会意外地使用来自另一个翻译单元的静态定义的变量/函数.

  • extern - 在此翻译单元中使用此变量/函数名称,但如果未定义,则不会抱怨.链接器将对其进行排序,并确保尝试使用某些extern符号的所有代码都具有其地址.

  • inline - 此功能将在多个翻译单元中定义,不用担心.链接器需要确保所有转换单元都使用变量/函数的单个实例.

注意:通常,声明模板inline是没有意义的,因为它们已经具有链接语义inline.但是,需要使用inline模板的专门化和实例化.private


您问题的具体答案:

  • 我应该何时在C++中为函数/方法编写关键字'inline'?

    仅当您希望在标题中定义函数时.更确切地说,只有当函数的定义可以显示在多个翻译单元中时.最好在头文件中定义小(如在一个线性中)函数,因为它为编译器提供了更多信息,以便在优化代码时使用.它还会增加编译时间.

  • 什么时候不应该为C++中的函数/方法编写关键字'inline'?

    不要仅仅因为您认为如果编译器内联它会使代码运行得更快而添加内联.

  • 什么时候编译器不知道何时使函数/方法'内联'?

    通常,编译器将能够比您更好地完成此操作.但是,如果编译器没有函数定义,则编译器无法内联代码.在最大限度优化的代码__attribute__(( noinline ))中,无论您是否要求,通常都会内联所有方法.

    另外,为防止在GCC中内联,请使用__declspec(noinline),并在Visual Studio中使用inline.

  • 当一个应用程序为函数/方法写入"内联"时,是否多线程是否重要?

    多线程不会以任何方式影响内联.

  • +1我在...中看到的内联的最佳描述(永远).我现在将把你扯掉并在我对inline关键字的所有解释中使用它. (156认同)
  • 每当我读到有关互联网累积知识*的内容时,我都要想到约翰劳顿的名言:[信息时代的讽刺之处在于它对不知情的观点给予了新的尊重.](http:// www. goodreads.com/quotes/152506-the-irony-of-the-information-age-is-that-it-has) (8认同)
  • @Ziggy,我想说的是编译器内联和`inline`关键字没有关系.你有正确的想法.通常,猜测内联将会改进什么是非常容易出错的.该规则的例外是一个衬里. (6认同)
  • 编译器只会内联函数调用,其中定义在调用站点可用.将所有函数保留在cpp文件中将限制对该文件的内联.我建议在.h中内联小的一个衬里,因为编译速度的成本可以忽略不计,并且几乎可以保证编译器会内联调用.关于编译器内联的观点是它是优化的黑色艺术的端口,你的编译器比你好得多. (5认同)
  • 这个答案让我有些困惑.你说所有关于编译器能够内联/不更好地内联的东西.然后你说你应该在头文件中放置一个衬里/小函数,并且编译器不能在没有函数定义的情况下内联代码.这些不是有点矛盾吗?为什么不把所有内容放在cpp文件中并让编译器决定? (4认同)
  • 如果提示,LLVM 将内联成本低于 225 或 325 的函数。对于规模 7 case switch 语句“成本”110,去虚拟化节省 100 成本。所以提示确实会影响编译器的内联决策,而且比我想象的要多(如果所有函数都被提示,人们会天真地期望内联增加 50%)。ignore 语句的目的是指出编译器内联了许多没有提示的函数,并忽略了复杂的提示函数。我会更新评论以使其更加清晰。 (4认同)
  • @RobertDailey,C++还没有模块支持.最多的编译器不知道标头是什么.当C++获得良好的模块支持时,你会认为不需要很多(全部?)`inline`s语义. (3认同)
  • @ legends2k:这里的链接是指一个符号可以在其编译单元之外使用.链接的这个方面由`extern`(默认...通常)和`static`控制.它被定义为具有"静态内联"或"外部内联"功能. (2认同)
  • 那么为什么专业人士使用FORCEINLINE.作为示例,UE4源代码具有许多内联方法.他们为什么让编译器进行内联? (2认同)
  • @deft_code"在头文件中定义小(如在一个线程中)函数是个好主意"现代编译器可以使用链接时间优化/整个程序优化,当使用这个时,在头文件中定义函数对于内联没有任何区别. (2认同)
  • 我通过简单地添加"内联"优化了几种算法,我的探测器告诉我有一个瓶颈.我不认为所有编译器总能超越人为干预.这个答案具有误导性和不完整性.请参考/sf/ask/135261801/ (2认同)
  • "所以大多数编译器都会忽略'提示'." 这显然是错误的.至少Clang和GCC使用inline关键字作为内联提示:https://blog.tartanllama.xyz/inline-hints/ (2认同)

Ala*_*off 48

我想通过一个令人信服的例子来为这个主题中的所有重要答案做出贡献,以驱散任何剩余的误解.

给出两个源文件,例如:

  • inline111.cpp:

    #include <iostream>
    
    void bar();
    
    inline int fun() {
      return 111;
    }
    
    int main() {
      std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun;
      bar();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • inline222.cpp:

    #include <iostream>
    
    inline int fun() {
      return 222;
    }
    
    void bar() {
      std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun;
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • 案例A:

    编译:

    g++ -std=c++11 inline111.cpp inline222.cpp
    
    Run Code Online (Sandbox Code Playgroud)

    输出:

    inline111: fun() = 111, &fun = 0x4029a0
    inline222: fun() = 111, &fun = 0x4029a0
    
    Run Code Online (Sandbox Code Playgroud)

    讨论:

    1. 即使你应该对你的内联函数有相同的定义,如果不是这样的话,C++编译器也不会标记它(实际上,由于单独的编译它没有办法检查它).确保这一点是你自己的责任!

    2. 链接器不会抱怨一个定义规则,如fun()声明的那样inline.但是,因为inline111.cppfun()由编译器处理的第一个转换单元(实际调用),所以编译器在inline111.cpp中首次调用遇到fun()它时进行实例化.如果编译器决定扩大从其他地方在你的程序在其呼叫(inline222.cpp),调用将被链接到从生产它的实例inline111.cpp(调用内部inline222.cpp也可能会产生一个该翻译单元中的实例,但它将保持不链接状态).实际上,从相同的打印输出中可以看出这一点.fun()fun()fun()&fun = 0x4029a0

    3. 最后,尽管inline建议,编译器实际上扩大了一行程序fun(),它忽略了彻底你的建议,这是明显的,因为fun() = 111在这两个线.


  • 案例B:

    编译 (注意逆序):

    g++ -std=c++11 inline222.cpp inline111.cpp
    
    Run Code Online (Sandbox Code Playgroud)

    输出:

    inline111: fun() = 222, &fun = 0x402980
    inline222: fun() = 222, &fun = 0x402980
    
    Run Code Online (Sandbox Code Playgroud)

    讨论:

    1. 本案例断言案例A中讨论过的内容.

    2. 请注意一个重要的观点,如果你注释掉实际调用fun()inline222.cpp(注释掉cout的语句来inline222.cpp完全),那么,尽管你的翻译单元的编译顺序,fun()将在它被实例化的第一个电话中相遇inline111.cpp,从而使打印出的情况B作为inline111: fun() = 111, &fun = 0x402980.


  • 案例C:

    编译 (注意-O2):

    g++ -std=c++11 -O2 inline222.cpp inline111.cpp
    
    Run Code Online (Sandbox Code Playgroud)

    要么

    g++ -std=c++11 -O2 inline111.cpp inline222.cpp
    
    Run Code Online (Sandbox Code Playgroud)

    输出:

    inline111: fun() = 111, &fun = 0x402900
    inline222: fun() = 222, &fun = 0x402900
    
    Run Code Online (Sandbox Code Playgroud)

    讨论:

    1. 正如这里所描述,-O2优化编译鼓励以实实在在地扩大可内联函数(另请注意,-fno-inline默认不优化选项).如从此处的outprint明显看出,fun()实际上已经被扩展内联(根据其在该定义特定翻译单元),得到两个不同的 fun()打印输出.尽管如此,仍然只有一个全球链接的实例fun()(根据标准的要求),从相同的 &fun打印输出中可以看出.

  • 你的答案是一个说明性的帖子,说明为什么语言使这种"内联"函数成为未定义的行为. (7认同)
  • C++ 参考明确指出“如果具有外部链接的内联函数或变量 (C++17 起) 在不同的翻译单元中定义不同,则行为未定义。”。因此,您编写的内容是 GCC 特定的,因为它是编译和链接过程编排的副作用。另请注意,这可能因版本而异。 (2认同)

Bos*_*gan 27

在进行模板特化时,如果专业化在.h文件中,您仍需要显式内联函数


Ari*_*yck 20

1)如今,几乎从来没有.如果内联函数是个好主意,编译器将在没有您帮助的情况下完成.

2)总是.见#1.

(编辑反映你把问题分成两个问题......)

  • -1:仍然需要`inline`,例如_define_头文件中的函数(这是在几个编译单元中内联这样一个函数所必需的). (2认同)
  • @Étienne 那是特定于实现的。根据标准,有一个定义规则,这意味着如果您天真地将函数定义包含在多个翻译单元中,您将收到错误。但是如果该函数具有 `inline` 说明符,它的实例会被链接器自动折叠成一个,并且不使用 ODR。 (2认同)

Joh*_*itb 12

什么时候不应该为C++中的函数/方法编写关键字'inline'?

如果该函数的定义.cpp文件,你应该写关键字.

什么时候编译器不知道何时使函数/方法'内联'?

没有这种情况.编译器无法使内联函数.它所能做的就是内联部分或全部函数调用.如果它没有得到函数的代码就不能这样做(在这种情况下,链接器需要这样做才能这样做).

当一个应用程序为函数/方法写入"内联"时,是否多线程是否重要?

不,这根本不重要.


小智 5

  • 什么时候编译器不知道何时使函数/方法'内联'?

这取决于使用的编译器.不要盲目相信现在的编译器比人类更了解如何内联,你不应该出于性能原因使用它,因为它是连接指令而不是优化提示.虽然我同意在意识形态上这些论点正确地遇到现实可能是另一回事.

在阅读了多个线程后,我尝试了好奇内联对我正在工作的代码的影响,结果是我为GCC获得了可测量的加速并且没有为英特尔编译器加速.

(更多细节:在类外定义的几个关键函数的数学模拟,GCC 4.6.3(g ++ -O3),ICC 13.1.0(icpc -O3);向关键点添加内联导致GCC代码加速+ 6%).

因此,如果您将GCC 4.6限定为现代编译器,结果是如果您编写CPU密集型任务并知道确切的瓶颈位置,则内联指令仍然很重要.

  • 我想看到更多证据来支持你的说法.请提供您正在测试的代码以及带有和不带内联关键字的汇编器输出.任何数量的东西都可以为您带来性能优势. (5认同)
  • 终于有人不仅重复别人所说的话,而且确实验证了这些陈述。Gcc 确实仍然将 inline 关键字视为提示(我认为 clang 完全忽略了它)。 (2认同)

归档时间:

查看次数:

115670 次

最近记录:

6 年,3 月 前