谨慎使用 static:如果只是想把函数定义写在头文件中,用 inline,不要用static。static 和 inline 不一样:
- static 的函数是内部链接,不同编译单元可以有同名的static 函数,但该函数只对 对应的编译单元 可见。如果同一定义的 static 函数,被不同编译单元调用,每个编译单元有自己单独的一份拷贝,且此拷贝只对 对应的编译单元 可见。
- inline 的函数是 external linkage,如果被不同编译单元调用,每个编译单元引用/链接的是同一函数,同一定义。
- 上面的不同直接导致:如果函数内有 static 变量,对inline 函数,此变量对不同编译单元是共享的(Meyer’s Singleton);对于static 函数,此变量不是共享的。看后面的代码就明白区别了。
static inline 函数,跟 static 函数单独没有差别,所以没有意义,只会混淆视听。
inline 函数的定义不一定要跟声明放在一个头文件里面:定义可以放在一个单独的头文件 .hxx 中,里面需要给函数定义前加上 inline 关键字,原因看下面第 2.点;然后声明 放在另一个头文件 .hh 中,此文件include 上一个 .hxx。这种用法 boost里很常见:优点1. 实现跟API 分离,encapsulation。优点2. 可以解决 有关inline 函数的循环调用问题:这个不展开说了,看一个这个文章就懂了:Headers and Includes: Why and How 第 7 章,function inlining。
指定inline
- 不要再把 inline 和编译器优化挂上关系了,不加inline,小函数编译器也会自动优化,看到inline时,应该首先想到其他用意,再考虑编译器优化。
- inline最大的用处是:非template 函数,成员或非成员,把定义放在头文件中,定义前不加inline ,如果头文件被多个cpp文件引用,编译会报错重定义。
static_inline_A.h文件:
#ifndef __STATIC_INLINE_A__
#define __STATIC_INLINE_A__
# include <iostream>
namespace static_test
{
volatile static int a = 10;
inline int& static_value() // (!*!) Or change this to inline
{
static int value = -1;
return value;
}
namespace A
{
void set_value(int val);
void print_value();
void set_static_value(int val);
void print_static_value();
}
}
#endif // __STATIC_INLINE_A__
static_inline_A.cpp文件:
# include "static_inline_A.h"
namespace static_test
{
namespace A
{
void set_value(int val)
{
auto& value = static_value();
value = val;
}
void print_value()
{
std::cout << static_value() << '\n';
}
void set_static_value(int val)
{
a = val;
}
void print_static_value()
{
std::cout << "A::a = " << a << std::endl;
}
}
}
static_inline_B.h文件:
#ifndef __STATIC_INLINE_B__
# define __STATIC_INLINE_B__
# include <iostream>
namespace static_test
{
namespace B
{
void set_value(int val);
void print_value();
void set_static_value(int val);
void print_static_value();
};
}
#endif // __STATIC_INLINE_B__
static_inline_B.cpp文件:
# include "static_inline_A.h"
# include "static_inline_B.h"
namespace static_test
{
namespace B
{
void set_value(int val)
{
auto& value = static_value();
value = val;
}
void print_value()
{
std::cout << static_value() << '\n';
}
void set_static_value(int val)
{
a = val;
}
void print_static_value()
{
std::cout << "B::a = " << a << std::endl;
}
}
}
测试代码:
# include "static_inline_A.h"
# include "static_inline_B.h"
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();
static_test::A::set_static_value(100);
static_test::A::print_static_value();
static_test::B::print_static_value();
static_test::B::set_static_value(200);
static_test::A::print_static_value();
static_test::B::print_static_value();
system("pause");
return 0;
}
输出:
注意:定义静态变量也是一样,在不同的文件引用会产生不同的静态变量。