When should I write the keyword 'inline' for a function/method?

后端 未结 15 2783
清歌不尽
清歌不尽 2020-11-21 06:55

When should I write the keyword inline for a function/method in C++?

After seeing some answers, some related questions:

  • When should I <

15条回答
  •  一整个雨季
    2020-11-21 07:17

    I'd like to contribute to all of the great answers in this thread with a convincing example to disperse any remaining misunderstanding.

    Given two source files, such as:

    • inline111.cpp:

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

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

    • Case A:

      Compile:

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

      Output:

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

      Discussion:

      1. Even thou you ought to have identical definitions of your inline functions, C++ compiler does not flag it if that is not the case (actually, due to separate compilation it has no ways to check it). It is your own duty to ensure this!

      2. Linker does not complain about One Definition Rule, as fun() is declared as inline. However, because inline111.cpp is the first translation unit (which actually calls fun()) processed by compiler, the compiler instantiates fun() upon its first call-encounter in inline111.cpp. If compiler decides not to expand fun() upon its call from anywhere else in your program (e.g. from inline222.cpp), the call to fun() will always be linked to its instance produced from inline111.cpp (the call to fun() inside inline222.cpp may also produce an instance in that translation unit, but it will remain unlinked). Indeed, that is evident from the identical &fun = 0x4029a0 print-outs.

      3. Finally, despite the inline suggestion to the compiler to actually expand the one-liner fun(), it ignores your suggestion completely, which is clear because fun() = 111 in both of the lines.


    • Case B:

      Compile (notice reverse order):

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

      Output:

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

      Discussion:

      1. This case asserts what have been discussed in Case A.

      2. Notice an important point, that if you comment out the actual call to fun() in inline222.cpp (e.g. comment out cout-statement in inline222.cpp completely) then, despite the compilation order of your translation units, fun() will be instantiated upon it's first call encounter in inline111.cpp, resulting in print-out for Case B as inline111: fun() = 111, &fun = 0x402980.


    • Case C:

      Compile (notice -O2):

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

      or

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

      Output:

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

      Discussion:

      1. As is described here, -O2 optimization encourages compiler to actually expand the functions that can be inlined (Notice also that -fno-inline is default without optimization options). As is evident from the outprint here, the fun() has actually been inline expanded (according to its definition in that particular translation unit), resulting in two different fun() print-outs. Despite this, there is still only one globally linked instance of fun() (as required by the standard), as is evident from identical &fun print-out.

提交回复
热议问题