c++ inline使函数实现可以在头文件中,避免多重定义错误

作者:Jon Lee
链接:https://www.zhihu.com/question/53082910/answer/133612920
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

inline 绝对是C++里最让人混淆的关键词之一了(比static还过分)。

============== 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 函数单独没有差别,所以没有意义,只会混淆视听。

5. inline 函数的定义不一定要跟声明放在一个头文件里面:定义可以放在一个单独的头文件 .hxx 中,里面需要给函数定义前加上 inline 关键字,原因看下面第 2.点;然后声明 放在另一个头文件 .hh 中,此文件include 上一个 .hxx。这种用法 boost里很常见:优点1. 实现跟API 分离,encapsulation。优点2. 可以解决 有关inline 函数的 循环调用问题:这个不展开说了,看一个这个文章就懂了:Headers and Includes: Why and How 第 7 章,function inlining。

Reference: inline specifier

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

1. 不要再把 inline 和编译器优化挂上关系了,太误导人。编译器不傻,inline is barely a request。你不加inline,小函数在开O3时,编译器也会自动给你优化了。看到inline时,应该首先想到其他用意,在考虑编译器优化。

2. inline最大的用处是:非template 函数,成员或非成员,把定义放在头文件中,定义前不加inline ,如果头文件被多个translation unit(cpp文件)引用,ODR会报错multiple definition。

============== 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

猜你喜欢

转载自www.cnblogs.com/l2017/p/10585700.html