c++ inline使函數實現能夠在頭文件中,避免多重定義錯誤

 

做者:Jon Lee
連接:https://www.zhihu.com/question/53082910/answer/133612920
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

inline 絕對是C++裏最讓人混淆的關鍵詞之一了(比static還過度)。ios

============== Update 30 Nov 2016函數

看其餘評論裏有提到static 的。我的評價一下 static + inline 一塊兒:那就是把死人往活裏搞,活人往死裏搞的趕腳,坑之深簡直不忍直視。先上追加的3個結論;後面有代碼,有耐心的小夥伴們拿回去本身試。優化

3. 謹慎使用 static:若是隻是想把函數定義寫在頭文件中,用 inline,不要用static。static 和 inline 不同:
  • static 的函數是 internal linkage。不一樣編譯單元能夠有同名的static 函數,但該函數只對 對應的編譯單元 可見。若是同必定義的 static 函數,被不一樣編譯單元調用,每一個編譯單元有本身單獨的一份拷貝,且此拷貝只對 對應的編譯單元 可見。
  • inline 的函數是 external linkage,若是被不一樣編譯單元調用,每一個編譯單元引用/連接的是同一函數,同必定義。
  • 上面的不一樣直接致使:若是函數內有 static 變量,對inline 函數,此變量對不一樣編譯單元是共享的(Meyer's Singleton);對於static 函數,此變量不是共享的。看後面的代碼就明白區別了。

4. static inline 函數,跟 static 函數單獨沒有差異,因此沒有意義,只會混淆視聽。this

5. inline 函數的定義不必定要跟聲明放在一個頭文件裏面:定義能夠放在一個單獨的頭文件 .hxx 中,裏面須要給函數定義前加上 inline 關鍵字,緣由看下面第 2.點;而後聲明 放在另外一個頭文件 .hh 中,此文件include 上一個 .hxx。這種用法 boost裏很常見:優勢1. 實現跟API 分離,encapsulation。優勢2. 能夠解決 有關inline 函數的 循環調用問題:這個不展開說了,看一個這個文章就懂了:Headers and Includes: Why and How 第 7 章,function inlining。spa

Reference: inline specifierblog

============== 原答案30 Nov 2016ip

1. 不要再把 inline 和編譯器優化掛上關係了,太誤導人。編譯器不傻,inline is barely a request。你不加inline,小函數在開O3時,編譯器也會自動給你優化了。看到inline時,應該首先想到其餘用意,在考慮編譯器優化。ci

2. inline最大的用處是:非template 函數,成員或非成員,把定義放在頭文件中,定義前不加inline ,若是頭文件被多個translation unit(cpp文件)引用,ODR會報錯multiple definition。get

============== static / inline 代碼編譯器


a.hh
#ifndef A_HH
# define A_HH

# include <iostream>

namespace static_test
{
  static int& static_value() // (!*!) Or change this to inline 
  {
    static int value = -1;
    return value;
  }

  namespace A
  {
    void set_value(int val);
    void print_value();
  }
}

#endif

  



a. cc

# include "a.hh"

namespace static_test
{
  namespace A
  {
    void set_value(int val)
    {
      auto& value = static_value();
      value = val;
    }
  
    void print_value()
    {
      std::cout << static_value() << '\n';
    }
  }
}

  



b.hh:

#ifndef B_HH
# define B_HH

# include <iostream>

namespace static_test
{ 
  namespace B
  {
    void set_value(int val);
    void print_value();
  };
}

#endif

  



b.cc:
# include "a.hh"
# include "b.hh"

namespace static_test
{
  namespace B
  {
    void set_value(int val)
    {
      auto& value = static_value();
      value = val;
    }
  
    void print_value()
    {
      std::cout << static_value() << '\n';
    }
  }
}
main. cc
# include "a.hh"
# include "b.hh"

int main()
{
  static_test::A::set_value(42);

  static_test::A::print_value();
  static_test::B::print_value();

  static_test::B::set_value(37);
  
  static_test::A::print_value();
  static_test::B::print_value();

  return 0;
}
  • a.hh 中標註 (!*!) 的那行,若是是inline,輸出:42,42,37,37。value 在整個程序中是個Singleton
  • 若是是 static,輸出:42,-1,42,37。value 在不一樣編譯單元是不一樣的拷貝,即便它被標註 static
相關文章
相關標籤/搜索