CppCoreGuidelines I.2 避免使用全局变量
09 March 2022
I.2: Avoid non-const global variables
理由
没有 const
修饰的全局变量,即可变全局变量,会隐藏依赖关系,从而导致不可预料的结果。比如:
struct Data { // ... lots of stuff ... } data; // non-const data void compute() // don't { // ... use data ... } void output() // don't { // ... use data ... }
可能还有其他地方会修改数据。这样的话, compute
计算出来的数据结果,在
output
函数中可能不是那个结果,因为中间其他某个地方也会修改这个数据。
警告
全局的对象初始化的时候,不一定完全按顺序进行。因此,如果一定要用全局变量,最好用常数设置全局对象的值。需要注意的是 const
对象的初始化顺序也是无序进行的。
例外
全局对象一般来说比单实例 singleton 好。
注意
全局常量自有其妙用。
此规则也适用于名字空间范围的变量。
其他选项
如果你要用全局(名字空间)变量来避免重复的复制传递参数,可以考虑以指向
const
的引用形式传递数据。另一个解决办法是把数据定义为某个对象的状态,把该数据的操作函数设计成对象的成员方法。
警告
小心避免数据竞争。如果一个线程能访问非局部数据(或作为引用传进来的数据),而另一个线程执行的时候修改该数据,就会造成数据竞争。任何可变数据的指针或引用都可能导致数据竞争。
使用全局指针或引用访问/修改非 const
,非全局的变量,依然避免不了隐藏的数据依赖关系,也可能导致数据竞争情况。
不可变数据不会造成竞争情况。
注意
当然也有例外情况,比如cin
, cout
,以及 cerr
.
强化
清点所有在名字空间作用域的非 const
变量,以及全局范围的指向非 const
数据的指针和引用。