不应在头文件中使用静态声明
4.5 ID_staticInHeader
头文件中由 static 关键字声明的对象、数组或函数,会在每个包含该头文件的翻译单元或模块中生成副本造成数据冗余,如果将静态数据误用作全局数据也会造成逻辑错误。
类的静态成员不受本规则限制。
示例:
// In a header file
static int i = 0; // Non-compliant
static int foo() { // Non-compliant
return i;
}
在编译每个包含该头文件的源文件时,变量 i 和函数 foo 都会生成不必要的副本。
在头文件中实现的内联或模板函数中,也不应使用静态声明,如:
// In a header file
inline void bar() {
static Type obj; // Non-compliant
....
}
如果该头文件被不同的模块(so、dll、exe)包含,obj 对象会生成不同的副本,很可能造成逻辑错误。
另外,由 const 或 constexpr 关键字限定的常量也具有静态数据的特性,在头文件中定义常量也面对这种问题,基本类型的常量经过编译优化可以不占用存储空间(有取地址操作的除外),而对于非基本类型的常量对象或数组也不应在头文件中定义,建议采用单件模式,将其数据定义在 cpp 等源文件中,在头文件中定义访问这些数据的接口,如:
// In arr.h
using Arr = int[256];
const Arr& getArr();
// In arr.cpp
#include "arr.h"
const Arr& getArr() {
static Arr a = {
1, 2, 3, ....
};
return a;
}
在需要用到常量数组的地方调用 getArr 函数,即可获取该数组的引用,没有任何重复的数据产生,并可保证数组在使用之前被有效初始化。
相关
依据
ISO/IEC 9899:1999 6.2.2(3)
ISO/IEC 9899:2011 6.2.2(3)
ISO/IEC 14882:2003 3.5(3)
ISO/IEC 14882:2011 3.5(3)