【问题标题】:When are global variables actually considered good/recommended practice?什么时候全局变量实际上被认为是好的/推荐的做法?
【发布时间】:2013-08-31 11:35:56
【问题描述】:

我已经阅读了很多关于为什么全局变量不好以及为什么不应该使用它们的文章。然而,大多数常用的编程语言都以某种方式支持全局变量。

所以我的问题是仍然需要全局变量的原因是什么,它们是否提供了一些无法替代实现的独特且不可替代的优势?与用户指定的自定义间接检索相比,全局寻址是否有任何好处以检索其本地范围之外的对象?

据我所知,在现代编程语言中,全局寻址带来的性能损失与计算内存地址的每个偏移量相同,无论是从“全局”用户内存开头的偏移量还是从this 或任何其他指针。因此,在性能方面,用户可以使用公共指针间接在需要它们的狭义情况下伪造全局变量,而不会损失实际全局变量的性能。还有什么?真的需要全局变量吗?

【问题讨论】:

  • 从这里你会得到一些信息。 stackoverflow.com/questions/176118/…
  • @Gangadhar - C 中没有名称空间,但在 C++ 中我可以与名称空间共享可见性,那么这与使用可见性仅限于需要的地方的全局有什么不同?
  • @user2341104 正如您所说,C 中没有命名空间。C 中不可能声明或定义全局,其可见性仅限于需要的地方(声明静态全局变量以限制范围除外的用法。)。并且我已将上面的链接与此行相关联**您必须问自己:在全球范围内是否真的需要**。这是您从那里获得的信息。

标签: c++ c global-variables


【解决方案1】:

全局变量通常不会因为它们的性能而坏,它们之所以不好是因为在大型程序中,它们很难封装所有内容 - 存在信息“泄漏”,通常很难弄清楚发生了什么开。

基本上,您的变量的范围应该只是您的代码既能工作又相对容易理解所需的范围,仅此而已。在打印出十二次表的程序中使用全局变量是可以管理的,但在数百万行的会计程序中使用它们并不是那么好。

【讨论】:

    【解决方案2】:

    我认为这是另一个类似于 goto 的主题 - 这是一个“宗教事物”。

    有很多方法可以“解决”全局变量,但如果您仍然在代码中的不同位置访问相同的内存位,您可能会遇到问题。

    全局变量对某些事情很有用,但绝对应该“小心”使用(比goto 更重要,因为误用的范围更大)。

    有两件事使全局变量成为问题: 1. 很难理解对变量做了什么。 2. 在多线程环境中,如果从一个线程写入全局并由任何其他线程读取,则需要某种同步。

    但有时全局变量非常有用。例如,拥有一个 config 变量,其中包含来自应用程序配置文件的所有配置值。另一种方法是将它存储在从一个函数传递到另一个函数的某个对象中,这只是额外的工作,没有任何好处。特别是如果配置变量是只读的。

    但是,总的来说,我建议避免使用全局变量。

    【讨论】:

    • +1 表示“宗教事物”和“一些对象从一个函数传递到另一个函数,额外的工作没有任何好处。” - 如果全局变量解决了一个需要传递 pseudo-global 对象的问题,那么出于某种被误导的纯洁感而使用后者是愚蠢的。我目前的项目是基于一个巨大的物体,它是同类中唯一的一个,并且浪费空间/时间在各处发射this 指针。我试着让它成为一个单例......然后意识到如果可能的话,使用 (A) static 变量和在静态作用域禁止的地方使用全局变量更有意义。毕竟都是 1 个程序。
    【解决方案3】:

    全局变量意味着全局状态。这使得无法在程序中存储给定部分或函数本地的重叠状态。

    例如,让我们将给定用户的凭据存储在整个程序中使用的全局变量中。现在升级我们的程序以同时允许多个用户将变得更加困难。如果我们只是将用户的状态作为参数传递给我们的函数,升级到多个用户的问题就会少很多。

    【讨论】:

      【解决方案4】:

      我的问题是仍然需要全局变量的原因是什么,

      有时您需要从许多不同的函数中访问相同的数据。这是你需要全局变量的时候。

      例如,我现在正在编写一段代码,如下所示:

      static runtime_thread *t0;
      
      void 
      queue_thread (runtime_thread *newt)
      {
         t0 = newt;
         do_something_else ();
      }
      
      void 
      kill_and_replace_thread (runtime_thread *newt)
      {
         t0->status = dead;
         t0 = newt;
         t0->status = runnable;
         do_something_else ();
      }
      

      注意:将以上内容视为某种混合的 C 和伪代码,让您了解全局在哪里真正有用。

      【讨论】:

      • 但是如果我只是在同一个命名空间中声明它们并在函数内部使用命名空间呢?
      • @user2341104 你误解了我的意思。如果您查看我为您编写的示例代码,您需要t0 可以被许多对其进行操作的函数全局访问(在同一个文件中,在这种特殊情况下)。您不能只将其定义为一个函数,因为如果您这样做,许多其他人将无法访问它。
      【解决方案5】:

      在编写任何跨平台库时,静态全局几乎是必需的。这些全局变量是静态的,因此它们保留在翻译单元中。很少有跨平台库不使用静态全局变量,因为它们必须向用户隐藏其平台特定的实现。这些平台特定的实现保存在静态全局变量中。当然,如果他们使用不透明指针并要求将平台特定的实现保存在这样的结构中,他们可以制作一个没有任何静态全局的跨平台库。但是,需要将这样的对象传递给此类库中的所有函数。因此,你可以到处传递这个不透明的指针,或者制作静态全局变量。

      还有标识符限制问题。编译器(尤其是较旧的编译器)对它们在一个范围内可以处理的标识符数量有限制。许多操作系统仍然使用大量的#define 而不是enumerations,因为它们的旧编译器无法处理使标识符膨胀的枚举常量。适当重写头文件可以解决其中的一些问题。

      【讨论】:

        【解决方案6】:

        当您想在包括 main 在内的每个函数中使用全局变量时,都会考虑全局变量。还要记住,如果你全局初始化一个变量,它的初始值在每个函数中都是相同的,但是你可以在函数内部重新初始化它,以便在该函数中为该变量使用不同的值。这样,您不必在每个函数中一次又一次地声明相同的变量。但是,是的,它们有时会造成麻烦。

        • 列表项

        全局名称随处可见。当您认为您正在使用本地时,您可能会在不知不觉中最终使用全局

        • 如果您在声明全局变量时出错,则必须将更改应用到整个程序,就像您不小心将其声明为 int 而不是 float

        【讨论】:

        • “如果你全局初始化一个变量,它的初始值在每个函数中都是相同的,但是你可以重新初始化它……在那个函数中为那个变量使用不同的值”……什么?不。要么您正在更改所有未来函数的全局变量以查看(即不是“初始值将相同”),要么您正在声明一个恰好具有相同名称的 不同 局部变量,隐藏全局并且无法离开函数的作用域。无论哪种情况,您都可能会过得很糟糕。
        猜你喜欢
        • 2012-05-18
        • 2010-12-06
        • 2014-01-12
        • 2016-05-26
        • 2010-10-22
        • 2011-11-20
        • 2014-11-05
        • 1970-01-01
        相关资源
        最近更新 更多