【问题标题】:C++ Inline methods for performance提高性能的 C++ 内联方法
【发布时间】:2012-09-13 20:15:55
【问题描述】:

很久以前有人告诉我,通过使用关键字 inline 并在头文件中写入主体来制作经常被内联调用的简短函数/方法。 这是为了优化代码,这样就不会产生实际函数调用的开销。

今天看起来怎么样?现代编译器(在这种情况下为 Visual Studio 2010)是否会自动内联这些短函数,还是自己仍然“有必要”这样做?

【问题讨论】:

  • "使用关键字 inline 或在头文件中写入正文。" 我认为您的意思是使用关键字inline 在标题中写入正文——如果你有多个翻译单元,只做一个而不做两个都会导致链接器错误。
  • 当然。我将编辑我的问题。
  • 这确实是大小问题:如果您经常调用函数(如数百万次),则函数调用开销很重要。实际上,我遇到过一种情况,该函数一开始有一个简单的if ( something ) return;。编译器无法内联它(或选择不内联),并且将此 if 语句移出函数对性能有很大影响。然而,在更改之前,该函数被调用了大约 2000 万次。它确实是一个启用了优化的现代编译器。所以总的来说:不要浪费你的时间

标签: c++ performance inline


【解决方案1】:

inline 一直是对编译器的提示,而如今,编译器在这方面大多自行决定(参见register)。

为了内联扩展函数,编译器必须查看该函数的定义。对于只在一个翻译单元中定义和使用的函数,这没问题:在使用之前将定义放在某处,编译器将决定是否内联函数。

对于在多个翻译单元中使用的函数,为了让编译器看到函数的定义,定义必须放在头文件中。当您这样做时,您需要标记函数inline 以告诉编译器和链接器该函数有多个定义是可以的。 (好吧,我想你可以创建函数static,但是你最终可能会浪费多个副本的空间)

【讨论】:

    【解决方案2】:

    启用警告C4710,如果您定义为内联的函数没有被编译器内联,这将警告您。

    启用警告C4711,如果编译器内联未指定用于内联的函数,这将警告您。

    这两个警告的结合将使您更好地了解编译器实际上对您的代码所做的事情,以及是否值得手动指定内联函数。

    【讨论】:

      【解决方案3】:

      一般而言,inline 关键字现在更多地用于允许您在头中定义函数时“违反”单一定义规则,而不是向编译器提示有关内联的提示。许多编译器非常擅长决定何时内联函数,只要函数体在调用点可见。

      当然,如果您仅在非内联源文件中定义函数,编译器将能够将其内联到该源文件中,但不能内联到任何其他翻译单元中。

      【讨论】:

      • +1 用于提及 ODR,但我认为 OP 问题的真正答案围绕 LTO。
      • 实际上 gcc 有 -flto 做这样的事情 afaik
      • @stefan -flto 用于链接时间优化。它与单一定义规则无关。马克的回答是正确的;启用 ODR 的“违规”(但不是真的)是 inline 所做的核心。 “内联”是一个额外的好处。关于“但不是真的”:inline 关键字修改而不是消除一个定义规则。文件 a.cpp 中的 inline int foo () {return 0} 和文件 b.cpp 中的 inline int foo () {return 1} 违反了单一定义规则。 inline int foo() 的所有定义必须相同,否则代码仍然违反 ODR。
      【解决方案4】:

      在以下情况下,编译器可以进行内联:

      1. 您将函数标记为inline 并且

        1. 在当前翻译单元或包含在其中的文件中定义;
        2. 编译器认为值得这样做。根据MSDN

          inline 关键字告诉编译器内联扩展是首选
          编译器将内联扩展选项和关键字视为建议。

      2. 您使用了 __forceinline 关键字(或 gcc 中的 __ attribute __((always_inline)))。这将使编译器跳过一些检查并为您执行内联。

        __forceinline 关键字覆盖了成本/收益分析,而是依赖于程序员的判断。

      3. 如果您通过将/GL 标志传递给编译器或将/LTCG 传递给链接器来打开link time code generation,Microsoft 编译器也可以执行跨模块内联。进行这样的优化非常聪明:尝试检查使用/LTCG 编译的模块的汇编代码。

      请注意,如果您的函数为:

      • 递归的;
      • 通过指向它的指针调用。

      【讨论】:

        【解决方案5】:

        是的,现代编译器将(取决于各种配置选项)自动选择内联函数,即使它们位于源文件(而不是头文件)中。使用 inline 指令可以给出提示。

        【讨论】:

          【解决方案6】:

          除了您的主要观点(在代码中放置多少内联指令对于当今的编译器来说很有用),请记住内联函数只是对编译器的提示,并不一定被编译为内联。

          【讨论】:

            【解决方案7】:

            简而言之,是的,编译器将决定您的函数是否变为inline。你可以检查这个问题:

            Does the compiler decide when to inline my functions (in C++)?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-12-19
              • 2018-11-06
              • 1970-01-01
              • 2011-06-27
              • 2019-03-20
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多