【问题标题】:When should I write the keyword 'inline' for a function/method?我应该什么时候为函数/方法编写关键字“内联”?
【发布时间】:2010-12-18 01:47:18
【问题描述】:

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

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

  • 我什么时候应该为 C++ 中的函数/方法编写关键字“内联”?

  • 编译器何时不知道何时将函数/方法设为“内联”?

  • 当为函数/方法编写“内联”时,应用程序是否是多线程是否重要?

【问题讨论】:

  • 如果您在标头中定义函数,则需要将其声明为内联。否则,您将收到有关函数的多个定义的链接器错误。
  • @Martin:除非它在类定义中,否则要挑剔。
  • @David:为了更加挑剔,这只是因为这些函数被隐式标记为inline (9.3/2)。
  • 另请参阅 C++ 常见问题解答中的 Inline Functions。他们对内联有很好的处理。

标签: c++ inline one-definition-rule


【解决方案1】:

哦,伙计,我最讨厌的事情之一。

inline 更像staticextern,而不是告诉编译器内联函数的指令。 externstaticinline 是链接指令,几乎只由链接器使用,而不是编译器。

据说inline 暗示编译器你认为该函数应该被内联。这在 1998 年可能是正确的,但十年后编译器不需要这样的提示。更不用说在优化代码时人类通常是错误的,所以大多数编译器完全忽略了“提示”。

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

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

  • inline - 这个函数会在多个翻译单元中定义,不用担心。链接器需要确保所有翻译单元都使用变量/函数的单个实例。

注意: 通常,声明模板inline 是没有意义的,因为它们已经具有inline 的链接语义。但是,要使用模板require inline 的显式特化和实例化。


您的问题的具体答案:

  • 什么时候应该为 C++ 中的函数/方法编写关键字“内联”?

    仅当您希望在标题中定义函数时。更准确地说,只有当函数的定义可以出现在多个翻译单元中时。在头文件中定义小(如在一个衬里)函数是一个好主意,因为它在优化代码时为编译器提供了更多信息。它还会增加编译时间。

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

    不要仅仅因为你认为如果编译器内联你的代码会运行得更快就添加内联。

  • 编译器何时不知道何时将函数/方法设为“内联”?

    一般来说,编译器会比你做得更好。但是,如果没有函数定义,编译器就没有内联代码的选项。在最大限度优化的代码中,无论您是否要求,通常所有 private 方法都会被内联。

    为了防止在 GCC 中内联,请使用 __attribute__(( noinline )),在 Visual Studio 中,请使用 __declspec(noinline)

  • 当为函数/方法编写“内联”时,应用程序是否为多线程是否重要?

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

【讨论】:

  • +1 我在...中看到的对内联的最佳描述(永远)。我现在将扯掉你,并在我对 inline 关键字的所有解释中使用它。
  • 这个答案让我有点困惑。您说了所有关于编译器能够更好地内联/不内联事物的内容。然后你说你应该在头文件中放置一个衬里/小函数,并且编译器不能在没有函数定义的情况下内联代码。这些是不是有点矛盾?为什么不把所有东西都放在 cpp 文件中,让编译器决定呢?
  • 编译器只会内联函数调用,其中定义在调用站点可用。将所有函数保留在 cpp 文件中会限制对该文件的内联。我建议在 .h 中内联定义小的 1 行,因为编译速度的成本可以忽略不计,并且几乎可以保证编译器会内联调用。我关于编译器内联的观点是,它是优化黑艺术的移植,在这方面你的编译器比你要好得多。
  • 每当我读到关于互联网累积知识的内容时,我都会想起约翰·劳顿的名言:The irony of the Information Age is that it has given new respectability to uninformed opinion.
  • “所以大多数编译器完全忽略了‘提示’。”这显然是错误的。至少 Clang 和 GCC 使用 inline 关键字作为内联的提示:blog.tartanllama.xyz/inline-hints
【解决方案2】:

我想通过一个令人信服的例子为这个帖子中的所有重要答案做出贡献,以消除任何剩余的误解。

给定两个源文件,如:

  • inline111.cpp:

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

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

  • 案例 A:

    编译

    g++ -std=c++11 inline111.cpp inline222.cpp
    

    输出

    inline111: fun() = 111, &fun = 0x4029a0
    inline222: fun() = 111, &fun = 0x4029a0
    

    讨论

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

    2. 链接器不会抱怨 One Definition Rule,因为 fun() 被声明为 inline。然而,由于 inline111.cpp 是编译器处理的第一个翻译单元(实际上调用 fun()),编译器在其 first 调用遇到时实例化 fun() inline111.cpp。如果编译器决定在从程序中的其他任何位置调用fun()例如来自inline222.cpp)时扩展fun(),则调用fun() 将始终链接到其从 inline111.cpp 生成的实例(在 inline222.cpp 中对 fun() 的调用也可能在该翻译单元中生成一个实例,但它将保持未链接状态)。确实,从相同的&amp;fun = 0x4029a0 打印输出中可以明显看出这一点。

    3. 最后,尽管inline 建议编译器实际扩展单行fun(),它完全忽略您的建议,即清除因为fun() = 111 在这两行中。


  • 案例 B:

    编译 (注意倒序)

    g++ -std=c++11 inline222.cpp inline111.cpp
    

    输出

    inline111: fun() = 222, &fun = 0x402980
    inline222: fun() = 222, &fun = 0x402980
    

    讨论

    1. 此案例主张案例 A 中讨论的内容。

    2. 请注意重要的一点,如果您在 inline222.cpp 中注释掉对 fun() 的实际调用(例如注释掉 cout-statement在 inline222.cpp 中)然后,尽管您的翻译单元的编译顺序,fun() 将在 inline111.cpp 中第一次调用遇到时被实例化,从而产生打印-案例 B 的输出为 inline111: fun() = 111, &amp;fun = 0x402980


  • 案例 C:

    编译 (注意-O2)

    g++ -std=c++11 -O2 inline222.cpp inline111.cpp
    

    g++ -std=c++11 -O2 inline111.cpp inline222.cpp
    

    输出

    inline111: fun() = 111, &fun = 0x402900
    inline222: fun() = 222, &fun = 0x402900
    

    讨论

    1. described here 一样,-O2 优化鼓励编译器实际扩展可以内联的函数(还要注意-fno-inline默认没有优化选项)。从这里的输出可以明显看出,fun() 实际上已经内联扩展(根据它在那个特定翻译单元中的定义),导致两个不同 fun() 打印输出。尽管如此,仍然只有一个fun() 的全局链接实例(按照标准的要求),从相同 &amp;fun 打印输出可以看出。

【讨论】:

  • 您的回答是一个说明性的帖子,说明为什么语言使此类 inline 函数成为未定义的行为。
  • 您还应该添加编译和链接分开的情况,每个.cpp 是它自己的翻译单元。最好为-flto 启用/禁用添加案例。
  • C++ 参考明确指出“如果具有外部链接的内联函数或变量(自 C++17 起)在不同的翻译单元中定义不同,则行为未定义。”。因此,您编写的内容是 GCC 特定的,因为它是编排编译和链接过程的副作用。另请注意,这可能因版本而异。
  • 我知道inline 告诉链接器允许符号冲突(坚持来自第一个翻译单元的符号),但是为什么不需要测试符号的等价性呢?该标准应要求编译器为所有内联函数提供 LTO 信息并强制进行此类检查!
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    2) 总是。见#1。

    (编辑以反映您将问题分为两个问题...)

    【讨论】:

    • 是的。内联只是对编译器的提示,可以随意忽略你。如今,编译器可能比程序员更清楚哪些函数最好内联。
    • 是的,但它的相关性较低 - 对于要内联的函数,它的主体必须在同一个编译单元中(例如,在标头中)。这在 C 程序中不太常见。
    • 定义非成员函数模板(又名非静态函数模板)不需要内联。见一个定义规则(3.2/5)。
    • -1: inline 仍然需要,例如在头文件中定义一个函数(这是在多个编译单元中内联此类函数所必需的) .
    • @Étienne 这是特定于实现的。根据标准,有一个定义规则,这意味着如果您天真地将函数定义包含在多个翻译单元中,则会出现错误。但是,如果该函数具有 inline 说明符,则链接器会自动将其实例合并为一个,并且不使用 ODR。
    【解决方案5】:

    什么时候不应该为 C++ 中的函数/方法编写关键字“内联”?

    如果函数在头文件中声明并在.cpp 文件中定义,则您应该编写关键字。

    编译器何时会不知道何时将函数/方法设为“内联”?

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

    当为函数/方法编写“内联”时,应用程序是否为多线程是否重要?

    不,这根本不重要。

    【讨论】:

    • 在某些情况下,在 .cpp 文件中使用内联是合适的。例如。将优化应用于完全特定于实现的代码。
    • @RobinDavies 更新了答案。看来你误解了我想写的内容。
    • @JohannesSchaub-litb 如果函数在头文件中声明并在.cpp文件中定义,则不应使用inline关键字。deft_code (967 次投票和接受的答案)提到与 当函数的定义可以显示在多个翻译单元中时,你应该只使用 inline 关键字所以我通过在头文件中使用关键字 @ 声明函数来检查它987654325@ 并在 .cpp 文件中定义它,它会给出错误undefined reference。所以你是对的。现在你也提到了,........继续下一条评论
    • @JohannesSchaub-litb ........ 编译器无法使用多个翻译单元中的函数代码,因此无法将它们内联,因此它是链接器工作 。从这个意义上说,deft_code 所以你应该使用 inline 关键字,这样它就可以为编译器提供更多信息。使用优化代码 所以他的措辞在这里也很有意义,但是当我尝试在前面提到的代码中使用它时会出错。所以我觉得你的两个陈述都是相互对立的,但它们都是有道理的,但是当我实际检查你的陈述是真的时,你能说明一下吗?
    【解决方案6】:
    • 编译器何时会不知道何时将函数/方法设为“内联”?

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

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

    (更多详细信息:在类外定义了少量关键函数的数学模拟,GCC 4.6.3 (g++ -O3),ICC 13.1.0 (icpc -O3);在关键点添加内联导致 GCC 代码加速 + 6% )。

    因此,如果您将 GCC 4.6 限定为现代编译器,那么如果您编写 CPU 密集型任务并且知道瓶颈到底在哪里,那么 inline 指令仍然很重要。

    【讨论】:

    • 我希望看到更多证据来支持您的说法。请提供您正在测试的代码以及带有和不带有 inline 关键字的汇编程序输出。任何事情都可以为您带来性能优势。
    • 终于有人不仅重复别人所说的,而且确实验证了这些陈述。 Gcc 确实仍然将 inline 关键字视为提示(我认为 clang 完全忽略了它)。
    • @void.pointer:为什么这么难以置信?如果优化器已经很完美,那么新版本就无法提高程序性能。但他们经常这样做。
    【解决方案7】:

    实际上,几乎从来没有。您所做的只是建议编译器将给定的函数内联(例如,替换对该函数的所有调用/w 它的主体)。当然,不能保证:编译器可能会忽略该指令。

    编译器通常会很好地检测和优化这样的事情。

    【讨论】:

    • 问题在于inline 在C++ 中具有语义 差异(例如处理多个定义的方式),这在某些情况下很重要(例如模板)。
    • inline 用于解决符号有多个定义的情况。然而,模板已经由语言处理。一个例外是不再具有任何模板参数的专用模板函数 (template)。这些被视为函数而不是模板,因此需要 inline 关键字才能链接。
    【解决方案8】:

    默认情况下,gcc 在编译时不会内联任何函数 启用优化。我不知道 Visual Studio – deft_code

    我通过使用 /FAcs 编译并查看汇编代码检查了 Visual Studio 9 (15.00.30729.01): 编译器在debug 模式下产生对成员函数的调用,但未启用优化。即使函数用 __forceinline 标记,也不会生成内联运行时代码。

    【讨论】:

    • 使 /Wall 能够被告知哪些函数标记为内联但实际上并未内联
    【解决方案9】:

    F.5:如果函数非常小且时间紧迫,则将其声明为内联

    原因:一些优化器擅长在没有程序员提示的情况下进行内联,但不要依赖它。措施!在过去 40 年左右的时间里,我们得到承诺,编译器可以在没有人类提示的情况下比人类更好地内联。我们还在等。指定内联(在类定义中编写成员函数时显式或隐式)鼓励编译器做得更好。

    来源:https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html#Rf-inline

    有关示例和例外情况,请转到源代码(见上文)。

    【讨论】:

      【解决方案10】:

      一个用例可能发生在继承上。例如,如果以下所有情况都为真:

      • 你有某个类的基类
      • 基类需要是抽象的
      • 基类除了析构函数之外没有纯虚方法
      • 你不想为基类创建cpp文件,因为徒劳

      那么你必须定义析构函数;否则,您将遇到一些undefined referance 链接器错误。此外,您不仅要定义,还要使用 inline 关键字定义析构函数;否则,您将遇到multiple definition 链接器错误。

      这可能发生在一些只包含静态方法或编写基础异常类等的帮助类中。

      举个例子:

      Base.h:

      class Base {
      public:
          Base(SomeElementType someElement) noexcept : _someElement(std::move(someElement)) {}
      
          virtual ~Base() = 0;
      
      protected:
          SomeElementType _someElement;
      }
      
      inline Base::~Base() = default;
      

      Derived1.h:

      #include "Base.h"
      
      class Derived1 : public Base {
      public:
          Derived1(SomeElementType someElement) noexcept : Base(std::move(someElement)) {}
      
          void DoSomething1() const;
      }
      

      Derived1.cpp:

      #include "Derived1.h"
      
      void Derived1::DoSomething1() const {
          // use _someElement 
      }
      

      Derived2.h:

      #include "Base.h"
      
      class Derived2 : public Base {
      public:
          Derived2(SomeElementType someElement) noexcept : Base(std::move(someElement)) {}
      
          void DoSomething2() const;
      }
      

      Derived2.cpp:

      #include "Derived2.h"
      
      void Derived2::DoSomething2() const {
          // use _someElement 
      }
      

      一般来说,抽象类除了构造函数和析构函数之外还有一些纯虚方法。因此,您不必将基类的虚拟析构函数的声明和定义分开,您可以在类声明上写virtual ~Base() = default;。但是,在我们的案例中,情况并非如此。

      据我所知,MSVC 允许您在类声明中编写类似的内容:virtual ~Base() = 0 {}。因此,您不需要使用 inline 关键字将 decleration 和定义分开。但它只适用于 MSVC 编译器。

      现实世界的例子:

      BaseException.h:

      #pragma once
      
      #include <string>
      
      class BaseException : public std::exception {
      public:
          BaseException(std::string message) noexcept : message(std::move(message)) {}
          virtual char const* what() const noexcept { return message.c_str(); }
      
          virtual ~BaseException() = 0;
      
      private:
          std::string message;
      };
      
      inline BaseException::~BaseException() = default;
      

      SomeException.h:

      #pragma once
      
      #include "BaseException.h"
      
      class SomeException : public BaseException {
      public:
          SomeException(std::string message) noexcept : BaseException(std::move(message)) {}
      };
      

      SomeOtherException.h:

      #pragma once
      
      #include "BaseException.h"
      
      class SomeOtherException : public BaseException {
      public:
          SomeOtherException(std::string message) noexcept : BaseException(std::move(message)) {}
      };
      

      main.cpp:

      #include <SomeException.h>
      #include <SomeOtherException.h>
      
      #include <iostream>
      
      using namespace std;
      
      static int DoSomething(int argc) {
          try {
              switch (argc) {
              case 0:
                  throw SomeException("some");
              case 1:
                  throw SomeOtherException("some other");
              default:
                  return 0;
              }
          }
          catch (const exception& ex) {
              cout << ex.what() << endl;
              return 1;
          }
      }
      
      int main(int argc, char**) {
          return DoSomething(argc);
      }
      

      【讨论】:

        【解决方案11】:

        除非您正在编写库或有特殊原因,否则您可以忘记inline 而使用链接时间优化。它消除了函数定义必须在标头中才能考虑跨编译单元内联的要求,这正是inline 所允许的。

        (但请参阅Is there any reason why not to use link time optimization?

        【讨论】:

          【解决方案12】:

          C++ 内联与C inline 完全不同。

          #include <iostream>
          extern inline int i[];
          int i [5];
          struct c {
            int function (){return 1;} // implicitly inline
            static inline int j = 3; // explicitly inline
            static int k; // without inline, a static member has to be defined out of line
            static int f (){return 1;} // but a static method does not // implicitly inline
          };
          
          extern inline int b;
          int b=3;
          int c::k = 3; // when a static member is defined out of line it cannot have a static
                        // specifier and if it doesn't have an `inline` specifier in the
                        // declaration or on the definition then it is not inline and always
                        // emits a strong global symbol in the translation unit
          
          int main() {
            c j;
            std::cout << i;
          }
          

          inline 本身会影响编译器、汇编器和链接器。这是对编译器的一个指令,如果它在翻译单元中使用,则只为这个函数/数据发出一个符号,如果是,那么就像类方法一样,告诉汇编器将它们存储在 .section .text.c::function(),"axG",@progbits,c::function(),comdat 或 @987654327 部分中@ 用于未初始化数据或.section .data.b,"awG",@progbits,b,comdat 用于初始化数据。模板实例化也在它们自己的 comdat 组中。

          这遵循.section name, "flags"MG, @type, entsize, GroupName[, linkage]。例如,部分名称是.text.c::function()axG 表示该部分是可分配的、可执行的并且在一个组中,即将指定一个组名(并且没有 M 标志,因此不会指定 entsize); @progbits 表示该部分包含数据且非空白; c::function() 是组名,并且该组具有comdat 链接,这意味着在所有目标文件中,遇到带有此组名并带有 comdat 标记的所有部分都将从最终可执行文件中删除,除了 1 即编译器确保存在翻译单元中只有一个定义,然后告诉汇编器将其放在目标文件中自己的组中(1 组中的 1 节),然后链接器将确保如果任何目标文件具有同名的组,然后只在最终的 .exe 中包含一个。 inline 和不使用 inline 之间的区别现在对汇编器可见,因此链接器也可以看到,因为汇编器没有将其存储在常规的 .data.text 等中,因为它们的指令。只有具有外部链接的内联符号才会被赋予像这样的外部 comdat 链接——静态链接(本地)符号不需要进入 comdat 组。

          inline 在类中的非静态方法声明中,如果方法被离线定义,则使方法内联,如果在翻译单元中未引用该方法,这将防止在翻译单元中发出该方法.通过将inline 放在行外定义上可以达到相同的效果。当一个方法在没有inline 说明符的情况下被离线定义并且类中的声明不是inline 时,它将始终在翻译单元中为该方法发出一个符号,因为它将具有外部链接而不是比外部 comdat 链接。如果该方法在类中定义,则它隐式为inline,这为其提供了外部comdat 链接而不是外部链接。

          static inline 在类中的成员上(与方法相反)使其成为static 成员(不涉及其链接——它具有其类的链接,可能是外部的)。 static inline 还允许在类中定义 static 类的成员,而不是需要在类中声明然后离线定义(定义中没有 static,这是不允许的-fpermissive)。 *static inline* 也使成员 inline 而不是 static inline -- inline 表示只有在翻译单元中引用定义时才会发出定义。以前,您必须在外联定义中指定 inline 才能使成员 inline

          由于static方法可以在类中定义,static inline对类中定义的static方法没有影响,它总是有外部链接,是一个静态方法,是inline。如果定义不正确,则必须使用inline 使其成为inline(即提供给外部comdat 链接而不仅仅是外部链接),并且static 仍然不能使用。

          static inline 在文件范围内只影响编译器。这对编译器意味着:只有在翻译单元中使用此函数/数据时才发出一个符号,并将其作为常规静态符号(存储在 .text /.data 中,而不使用 .globl 指令)。对于汇编程序来说,staticstatic inline 现在没有区别。与inline 的其他形式一样,它不能用于class,它是一种类型,但可以用于该类类型的对象。这种形式的static inline 也不能用于函数的成员或方法,因为inline 总是被视为在类中的其他东西(这意味着该类充当范围而不是而不是作为对象的成员或方法使用)。

          extern inline 是一个声明,意味着您必须在翻译单元中定义此符号,如果它被引用或抛出编译器错误;如果已定义,则将其视为常规 inline,对于汇编器和链接器,extern inlineinline 之间没有区别,因此这只是编译器保护。

          extern inline int i[];
          extern int i[]; //allowed repetition of declaration with incomplete type, inherits inline property
          extern int i[5]; //declaration now has complete type
          extern int i[5]; //allowed redeclaration if it is the same complete type or has not yet been completed
          extern int i[6]; //error, redeclaration with different complete type
          int i[5]; //definition, must have complete type and same complete type as the declaration if there is a declaration with a complete type
          

          上面没有错误行的整个折叠到inline int i[5]。显然,如果你做了extern inline int i[] = {5};,那么extern 将被忽略,因为通过赋值进行了显式定义。

          我认为 static 不允许在没有 -fpermissive 的情况下出现在 static 外线定义上的原因是因为它暗示静态引用 static 链接,因为它不是立即显而易见的程序员,它是一个类的成员,或者该类是否具有,static 意味着不同的东西。 -fpermissive 忽略了外部定义中的 static 说明符,它没有任何意义。在简单整数的情况下,k 不能在命名空间之外定义,如果 c 是命名空间,但如果 k 是函数,则无法从行中明显看出无论是在命名空间中使用static 链接的函数的外线定义,还是带有外部链接的静态成员的外线定义,都可能给程序员/读者留下错误的印象代码。

          对于本地类,成员/方法上的inline 将导致编译器错误并且成员和方法没有链接。

          对于命名空间上的inline,请参阅thisthis

          【讨论】:

            【解决方案13】:

            Inline 关键字要求编译器将函数调用替换为函数体,它首先计算表达式然后传递。它减少了函数调用开销,如函数参数不需要存储返回地址和堆栈内存。

            何时使用:

            • 提高性能
            • 减少调用开销。
            • 由于它只是对编译器的请求,某些函数不会被内联 *大功能
              • 具有太多条件参数的函数
              • 递归代码和循环代码等

            【讨论】:

            【解决方案14】:

            你想把它放在最开始,在返回类型之前。但大多数编译器忽略它。如果它被定义,并且它有一个更小的代码块,大多数编译器无论如何都会认为它是内联的。

            【讨论】:

              【解决方案15】:

              在开发和调试代码时,请不要使用inline。它使调试变得复杂。

              添加它们的主要原因是帮助优化生成的代码。通常这会以增加的代码空间换取速度,但有时inline 会节省代码空间和执行时间。

              在算法完成之前扩展这种关于性能优化的想法是premature optimization

              【讨论】:

              • inline 函数通常不会内联,除非使用优化进行编译,因此它们不会以任何方式影响调试。请记住,这是一个提示,而不是一个要求。
              • gcc 默认情况下在未启用优化的情况下编译时不会内联任何函数。我不了解视觉工作室
              • 我参与了一个启用了调试的巨大 g++ 项目。也许其他选项阻止了它,但 inline 函数已内联。在它们中设置有意义的断点是不可能的。
              • 启用调试不会停止 gcc 中的内联。如果启用了任何优化(-O1 或更高),则 gcc 将尝试内联最明显的情况。传统上,GDB 很难使用断点和构造函数,尤其是内联构造函数。但是,这已在最近的版本中得到修复(至少 6.7,也许更快)。
              • 添加 inline 对改进现代编译器的代码没有任何帮助,现代编译器可以自行判断是否内联。
              【解决方案16】:

              什么时候应该内联:

              1.当一个人想避免调用函数时发生的事情的开销,如参数传递、控制转移、控制返回等。

              2.函数要小,经常调用,内联是非常有利的,因为按照80-20规则,尽量将那些对程序性能有重大影响的函数内联。

              正如我们所知,内联只是对编译器的请求,类似于注册,它会花费您的对象代码大小。

              【讨论】:

              • "inline 只是对编译器的请求,类似于 register" 它们是相似的,因为它们既不是请求,也与优化无关。 inline 已失去其作为优化提示的地位,并且大多数编译器仅使用它来允许多个定义 - 正如 IMO 应有的那样。更重要的是,自 C++11 以来,register 已完全被弃用,因为其先前的含义是“我比编译器更了解如何优化”:它现在只是一个没有当前含义的保留字。
              • @underscore_d:在某种程度上,Gcc 仍然在听inline
              猜你喜欢
              • 2012-01-14
              • 2010-09-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-12-11
              • 1970-01-01
              • 2011-06-30
              相关资源
              最近更新 更多