本节书摘来自异步社区出版社《c++覆辙录》一书中的第1章,第1.3节,作者: 【美】stephen c. dewhurst(史蒂芬 c. 杜赫斯特),更多章节内容可以访问云栖社区“异步社区”公众号查看。
很难找到任何理由去硬生生地声明什么全局变量。全局变量阻碍了代码重用,而且使代码变得更难维护。它们阻碍重用是因为任何使用了全局变量的代码就立刻与之耦合,这使得全局变量一改它们也非得跟着改,从而使任何重用都不可能了。它们使代码变得更难维护的原因是很难甄别出哪些代码用了某个特定的全局变量,因为任何代码都有访问它们的权限。
全局变量增加了模块间的耦合,因为它们往往作为幼稚的模块间消息传递机制的设施存在。就算它们能担此重任,从实践角度来说8,要从大型软件的源代码中去掉任何全局变量都几乎不可能9。这还是说他们能正常工作的情况。不过可不要忘了,全局变量是不设防的。随便哪个维护你代码的c++ 新手都能让你对全局变量有强烈依赖的软件所玩的把戏随时坍台。
全局变量的辩护者们经常拿它的“方便”来说事。这真是自私自利之徒的无耻之争。要知道,软件的维护常常比它的初次开发要花费更多时间,而使用全局变量就意味着把烂摊子扔给了维护工程师。假设我们有一个系统,它有一个全局可访问的“环境”,并且我们按需求保证确实只有“一个”。不幸的是,我们选择了使用全局变量来表示它:
`
extern environment * const theenv; `
我们的需求一时如此,但马上就行不通了。在软件就要交付之前,我们会发现,可能同时存在的环境要增加到两个、三个或是在系统启动时指定的或根本就是完全动态的某个数。这种在软件发布的最后时刻发生的变更实属家常便饭。在备有无微不至的源代码控制过程的大项目里,这个变更会引发极费时间、涉及所有源文件的更改,即使在最细小的和最直截了当的那些地方也不例外。整个过程预计要几天到几星期不等。假如我们不用全局变量这个灾星,只要5分钟我们就能搞定这一切:
environment *theenv();`
仅仅是把对于值的访问加了函数的包装,我们就获得了可贵的可扩充性。要是再加上函数重载,或是给予函数形参以默认值,我们就根本不要怎么改源代码了:
environment *theenv( envcode whichenv = official );`
另一个全局变量引起的问题并不能一望即知。此问题的来源是全局变量经常要求延迟到运行期才进行的静态初始化。c++语言里如果静态变量用来初始化的值不能在编译期就计算妥当,那么这个初始化的动作就会被拖到运行期。这是许多致命后果的始作俑者(此问题非常重要,常见错误55专门来讨论此问题):
class environment {
public:
static environment &instance();
virtual void op1() = 0;
// ...
protected:
environment();
virtual~environment();
private:
static environment *instance_;
};<code>`</code>