全局变量(再次)

Bar*_*uch 2 c++ global-variables

我一直听说应该使用全局变量,但我倾向于将" 从不 "规则视为头脑冷静.真的没有例外吗?
例如,我目前正在用SDL用c ++编写一个小游戏.在我看来,有一个带有指向屏幕缓冲区的指针的全局变量很有意义,因为代表游戏中不同类型的东西的所有不同的类都需要对它进行blit,并且只有一个屏幕缓冲区.

请告诉我,如果我是对的,有异常,或者如果没有,那么:

  • 为什么不,或者对他们有什么不好,他们应该不惜一切代价避免(请解释一下)
  • 如何实现这一点,最好不必将其传递给每个要在内部存储的构造函数,直到需要,或者每次调用paint()请求.

(我会假设这个问题之前已被问过,但在搜索时无法找到我需要的东西(解释和解决方法).如果有人可以发布前一个问题的链接,那可能会很棒)

JOT*_*OTN 8

我们告诉学生永远不要使用全局变量,因为它鼓励更好的编程方法.这与我们告诉他们不使用goto语句的原因相同.一旦你成为一名有成就的程序员,你就可以违反规则,因为你应该知道什么时候合适.


Zac*_*oom 7

与任何其他设计决策一样,使用全局变量会产生成本.它可以节省您不必要地传递变量,并允许您在运行的函数之间共享状态.但它也有可能使您的代码难以遵循和重用.

某些应用程序(如嵌入式系统)会定期使用全局变量.对于他们来说,不必将变量甚至指针传递到激活记录中的附加速度和简单性使得它成为一个好的决定[可以说].但是他们的代码受到了损害; 通常很难遵循执行,开发复杂程度越来越高的系统变得越来越困难.

在由异构组件组成的大型系统中,使用全局变量可能成为维护的噩梦.在某些时候,你可能需要一个具有不同属性的不同屏幕缓冲区,或者屏幕缓冲区可能无法使用,直到它被初始化意味着你必须用它来包装每个调用它是否为空,或者你需要写多线程代码,全局需要锁定.

简而言之,当您的应用程序足够小以便管理时,您可以自由使用全局变量.当它开始增长时,它们将成为一种责任,并且要么需要重构才能消除,或者将削弱程序的增长(在能力或稳定性方面).不使用它们的警告源于多年的艰苦学习课程,而不是程序员"头脑冷静".


jal*_*alf 7

当然,也有例外.我个人无法想到一个单一的情况,即goto是正确的解决方案(或单例是正确的解决方案),但全局变量偶尔会有其用途.但是......你没有找到有效的借口.

在游戏中做的大部分对象重复,需要访问屏幕缓冲区.这是渲染器的责任,而不是其他人.您不希望您的记录器,输入管理器,AI或任何其他人在屏幕上放置随机垃圾.

这就是人们说"不要使用全局"的原因.这不是因为全球化是某种最终的邪恶,但是因为如果我们不这样说,人们会陷入你所处的陷阱,"是的,但这条规则不适用于,对吧?我需要一切可以访问X".不,你需要学习构建你的程序.

更常见的异常是无状态或静止的物体,就像一个记录器,或者您的应用程序的配置:事物是只读或只写,哪些真正需要从访问无处不在.每行代码都可能需要编写日志消息.因此,记录器是制作全球的公平候选者.但99%的代码甚至不需要知道屏幕缓冲区存在.

简而言之,全局变量的问题是它们违反了封装:依赖于全局的代码不太可重用.我可以选择你正在使用的完全相同的课程,把它放在我的应用程序中,它会破坏.因为我没有相同的全局对象网络.

它还使代码更难以推理.函数f(x)返回什么值?这显然取决于什么x.但如果我x 两次通过相同的结果,我会得到相同的结果吗?如果它使用了很多全局变量,那么可能不会.然后,它变得非常困难,只是弄清楚它要回来,还什么别的是要做的事情.是否会设置一些会影响其他看似无关的函数的全局变量?

如何实现这一点,最好不必将其传递给内部存储的每个构造函数,直到需要为止

你觉得这听起来很糟糕.如果一个对象需要知道屏幕缓冲区,那么你应该给它屏幕缓冲区.在构造函数中,或在稍后的调用中.(并且它有一个很好的奖励:它会提醒你,如果你的设计很草率.如果你有500个类需要使用屏幕缓冲区,那么你必须将它传递给500个构造函数.这很痛苦,所以这是一个唤醒call:我做错了.很多对象不需要知道屏幕缓冲区.我该怎么解决这个问题?`)

作为一个更明显的例子,假设我想计算1.42的余弦,所以我将1.42传递给函数: cos(1.42)

这就是我们通常的做法,没有全局变量.当然,我们可以说"是的但是每个人都需要能够设定论证cos,我最好把它变成全球性的".然后它看起来像这样:

gVal = 1.42;
cos();
Run Code Online (Sandbox Code Playgroud)

我不了解你,但我认为第一个版本更具可读性.