我应该使用全局变量吗?

时间:2011-07-16 11:31:48

标签: c++ singleton g++ global

我一直在阅读关于全局变量以及它们有多糟糕但我因此被困在一个地方。我将非常具体地说明在这种情况下我是否应该使用全局变量。

我正在开发游戏引擎。我的引擎由很多经理组成。管理人员执行某些任务 - 他们存储资源,加载资源,更新资源等等。

我让所有经理都成了单身人士,因为很多课程和职能需要访问它们。我正在考虑删除单身人士,但我不知道我怎么也不能拥有它并且可以访问这些经理。

以下是我想说的一个例子(我的英文不好,对不起):

Singleton.h

template<class T> class Singleton {
private:
    Singleton( const Singleton& );
    const Singleton& operator=( const Singleton& );

protected:
    Singleton() { instance = static_cast<T*>(this); }
    virtual ~Singleton() {}

protected:
    static T * instance;

public:
    static T &Instance() {
        return *instance;
    }

};

ScriptManager.h

class ScriptManager : public Singleton<ScriptManager> {
public:
    virtual void runLine(const String &line)=0;
    virtual void runFile(const String &file)=0;
};

PythonScriptManager.cpp

class PythonScriptManager : public ScriptManager {
public:
    PythonScriptManager() { Py_Initialize(); }
    ~PythonScriptManager() { Py_Finalize(); }

    void runFile(const String &file) {
        FILE * fp = fopen(file.c_str(), "r");
        PyRun_SimpleFile(fp, file.c_str());
        fclose(fp);
        fp=0;
    }

    void runLine(const String &line) {
        PyRun_SimpleString(line.c_str());   
    }

};

实体ScriptComponent

#include <CoreIncludes.h>
#include <ScriptManager.h>
#include <ScriptComponent.h>

void update() {

    ScriptManager::Instance().runFile("test_script.script");
    //i know its not a good idea to open the stream on every frame but thats not the main concern right now.
}

应用

int main(int argc, const char * argv) {
    Application * app = new Application(argc, argv);
    ScriptManager * script_manager = new PythonScriptManager;
    //all other managers

    return app->run();
}

如你所见,我甚至没有在我的ScriptComponent.cpp文件中包含上面的文件,这使我获得了一些编译时间。如何在没有全局变量的情况下获得那种结果,这样可以很容易地集成到这个结果中。单例不是线程安全的,但添加线程不会花费很长时间。

我希望我能解释一下这个问题。

提前致谢,
Gasim Gasimzada

3 个答案:

答案 0 :(得分:26)

我不会说你从不使用全局变量,但是:

  • 从不使用单身人士。 Here就是为什么。它们太可怕了,而且它们比普通的老式全球更糟糕。
  • “经理”课程很糟糕。他们“管理”了什么?他们如何“管理”它? “经理”课程需要分解为您可以描述的内容。一旦弄清楚“管理”对象意味着什么,就可以定义一个或多个具有更明确职责的对象。
  • 当你使用全局变量时,不要让它们变得可变。只写全局是可以接受的(考虑一个记录器。你写它,但它的状态永远不会影响应用程序),只读全局变量也可以(考虑从不改变的各种常量,但你经常需要阅读)。全局变为有害的地方是当它们具有可变状态时:当你同时阅读和写下它们时。

最后,非常简单的替代方案: 只需将依赖项作为参数传递。如果一个对象需要某些东西才能运行,那么在它的构造函数中传递“something”。如果某个函数需要某些东西才能运行,那么将“某事”作为参数传递给它。

这可能声音就像许多工作一样,但事实并非如此。当你的设计混杂着全球和单身时,你会得到一个巨大的意大利面条建筑,一切都取决于其他一切。因为依赖关系没有明确可见,所以你得到了草率,而不是思考关于连接两个组件的最佳方式是什么,你只需要通过一个或多个全局变量进行通信。一旦你必须考虑明确传递哪些依赖关系,大多数依赖关系都是不必要的,并且你的设计变得更清晰,更易读和可维护,并且更容易推理。并且您的依赖项数量将急剧下降,因此您实际上只需要将一个或多个参数传递给少量对象或函数。

答案 1 :(得分:4)

如何删除ScriptManager基类并在专门化类中使用静态方法?看起来没有涉及任何ScriptManagers的状态,除了纯粹的虚函数之外没有真正的遗产。

如果你真的在这里使用多态,我无法从你的代码示例中找出答案。如果没有,静态成员函数对我来说看起来不错。

答案 2 :(得分:3)

不要使用全局变量。如果你需要一个类型的对象,那么你可以在必要时通过引用传入它。