【问题标题】:Use of global variables in C++ application在 C++ 应用程序中使用全局变量
【发布时间】:2015-05-11 00:48:22
【问题描述】:

我使用全局变量没有任何明显问题,但想知道我使用全局变量是否存在潜在问题或缺点。

在第一个场景中,我将 const 全局变量包含到 globals.h 文件中,然后将标头包含到需要访问任何一个全局变量的各种实现文件中:

globals.h
const int MAX_URL_LEN = 100;
const int MAX_EMAIL_LEN = 50;
…

在第二种情况下,我在应用程序执行时在实现文件中声明并初始化全局变量。这些全局变量永远不会再被修改。当我需要从不同的实现文件访问这些全局变量时,我使用 extern 关键字:

main.cpp
char application_path[128];
char data_path[128];
// assign data to globals
strcpy(application_path,  get_dll_path().c_str());
…

do_something.cpp
extern char application _path[]; // global is now accessible in do_something.cpp

关于上面的第一种情况,我考虑过删除所有不同的“include globals.h”,并在需要访问这些全局变量的地方使用 extern,但没有这样做,因为只包含 globals.h 非常方便。

我担心每个包含 globals.h 的实现文件会有不同版本的变量。

我应该使用 extern 而不是在需要访问的任何地方都包含 globals.h 吗?

请指教,谢谢。

【问题讨论】:

  • 建议:常量很好,但不要使用全局变量。根据需要传递数据或对象。
  • 你可能想看看这个关于全局变量的整体:stackoverflow.com/questions/484635/are-global-variables-bad
  • 您可以将extern something; 放在标题中,然后包含该标题以手动编写外部变量。此外,您不得在全局命名空间中使用以_ 开头的名称(因为标准是这样规定的)。
  • 我强烈建议创建提供对全局数据的访问权限的函数,例如 extern char const* get_application_path();,而不是提供对数据的直接访问权限。

标签: c++ extern globals


【解决方案1】:

你的实现现在很好。当全局变量成为问题时

  1. 您的程序在增长,您的全局变量数量也在增长。
  2. 新加入团队的人不知道你在想什么。

当您的程序变成多线程时,数字 1 变得特别麻烦。然后您有许多线程使用相同的数据,您可能需要保护,这对于仅使用全局变量列表是很困难的。 通过根据某些标准(例如目的或主题)将数据分组到单独的文件中,您的代码会随着代码的增长而变得更易于维护,并且您可以为项目中的新程序员留下面包屑以了解软件的工作原理。

【讨论】:

  • 关于“你的实现现在很好”,绝对不是。将逻辑常量公开为可变全局变量是非常不好的。
  • Alf:你的观点是正确的,但有时快速而肮脏的东西对于你想要完成的事情来说是完美的,特别是如果你不知道更好的话。
  • @LightnessRacesinOrbit:我从不回复 cmets。
【解决方案2】:

全局变量的一个问题是,当您在代码中包含第 3 方库时,有时它们会使用与您的名称相同的全局变量。有时候全局是有意义的,但如果可能的话,你也应该注意做一些事情,比如把它放到一个命名空间中。

【讨论】:

    【解决方案3】:

    全局可变变量

    • 在所有代码中提供不可见的影响线,并且
    • 您不能依赖它们的值,或者它们是否已被初始化。

    也就是说,全局可变变量对数据流的作用就像全局goto曾经对执行流所做的那样,造成了意大利面的混乱,浪费了大家的时间。

    常量全局变量更好,但即使是你遇到的那些

    • 初始化顺序惨败。

    我记得当我意识到我在包装一个众所周知的 GUI 框架时遇到的所有麻烦都是由于它不必要地使用了全局变量并引发了初始化顺序的失败时,我是多么生气。首先,愤怒是针对作者的,然后是针对我自己的愚蠢,没有意识到发生了什么(或者更确切地说,没有发生)。无论如何。

    解决所有这些问题的一个明智的方法是迈耶斯的单身人士,比如

    inline
    auto pi_decimal_digits()
        -> const string&
    {
        static const string the_value = compute_pi_digits();
        return the_value;
    }
    

    对于从某个知道值的地方动态初始化的全局变量,“一个程序员的常量是另一个程序员的变量”,没有好的解决方案,但一个实际的解决方案是接受运行时错误的可能性并至少检测到它:

    namespace detail {
        inline
        auto mutable_pi_digits()
            -> string&
        {
            static string the_value;
            return the_value;
        }
    }  // namespace detail
    
    inline
    void set_pi_digits( const string& value )
    {
        string& digits = detail::mutable_pi_digits();
        assert( digits.length() == 0 );
        digits = value;
    }
    
    inline
    auto pi_digits()
        -> const string&
    { return detail::mutable_pi_digits(); }
    

    【讨论】:

    • “全球goto”是什么意思?它的“全球性”是什么?
    • @LightnessRacesinOrbit:C 和 C++ 缺少全局 goto,除非你算上 longjmp
    • 是的,我知道;这就是为什么我问你为什么在 C++ 答案中提到假设的“全局goto”。
    • @LightnessRacesinOrbit:哦。我提到了历史。具体来说,一个叫 Edsger Dijkstra 的人曾经写过一篇文章,现在很有名,叫做“GOTO 被认为是有害的”。我认为它可以作为经典从 ACM 获得。本文使用whileif 等控制流结构为当时的结构化编程 铺平了道路。但是 Dijkstra 讨论的问题不是由 C 或 C++ 本地 goto 引起的那种问题,至少在普通的小函数中不会。这些问题是由(非常真实的)不受限制的全局goto 功能引起的。
    • 您应该阅读 1987 年出版的《'GOTO 被认为有害'被认为有害》。它令人大开眼界。
    猜你喜欢
    • 2015-05-26
    • 2010-11-12
    • 1970-01-01
    • 1970-01-01
    • 2014-05-11
    • 1970-01-01
    • 1970-01-01
    • 2018-03-14
    • 1970-01-01
    相关资源
    最近更新 更多