声明全局变量的最佳方法是什么?

时间:2009-03-11 17:58:55

标签: c++ design-patterns

在C ++中,假设您要声明一个全局变量供许多人使用。你是怎么做到的?

我通常在cpp文件中使用declare和define,然后在其他cpp文件中使用extern(而不是标题)。

我不喜欢这种做法,我正在考虑这些方面:

在头文件中:

some_file.h

Class MYGlobalClass
{

};


MyGlobalClass& MyGlobalClassInstance()
{
   static MYGlobalClass instance; 
   return  instance;

}

修改

请考虑以下情况:

  • 可用于多线程应用程序
  • 命名空间污染
  • 可能不需要单身,因为可能会创建许多实例

您有什么想法,建议,新想法?

8 个答案:

答案 0 :(得分:10)

最好的建议可能是“尽量避免全局”。人们不像他们想象的那样经常需要全局变量。通常情况下,“将所有内容作为参数传递给构造函数”并不像人们在听到建议时所想的那么多。它还倾向于使代码更清晰,具有更少,更明确的依赖性。

我不知道在C ++中声明全局变量的任何“正确”方法。你现在的方式工作正常,但初始化的顺序是未指定的,所以如果你的全局变量之间存在任何依赖关系,那你就麻烦了。

返回静态实例的函数或多或少地解决了这个问题,但不是线程安全的。

单身只是一个可怕的想法。它不能解决您的问题,但会为您的代码添加额外的限制,这些限制实际上并不是必需的,并且很可能会在以后再次出现并咬你。

答案 1 :(得分:4)

在“many”包含的一个头文件中声明为extern,并在一个* .cpp文件中定义

答案 2 :(得分:2)

您对存取器函数内部静态的想法与全局变量有很大不同。不同之处在于构造时,并且最有可能是多线程的主要问题。如果两个线程同时调用MyGlobalClassInstance怎么办?根据环境的不同,但我怀疑这是大多数C ++编译器的典型特征,您可能会同时运行MyGlobalClass的构造函数的两次调用,同时处理相同的内存区域。

如果你是单线程的话,它不太可能成为问题。

如果您将实例声明为普通静态成员或源文件中的普通全局变量,您可能会有更轻松的时间,因为构造函数将在main执行之前被调用,之后有机会开始其他线程。

答案 3 :(得分:2)

在一个头文件中声明它(使用extern),并在 one .cpp(或其他任何扩展名)文件中定义它。您可以使用函数并返回对静态变量的引用,就像您展示的一样,以避免相对于其他.cpp文件中的其他此类命名空间范围变量的构造顺序问题。但请记住,这不会保护您免受破坏顺序问题的影响 - 这与构造完全相反(这些东西称为“静态初始化顺序惨败”。如果您使用类似于您的函数并将其放入标题中,请将其内联当函数被包含在多个.cpp文件中时,重新定义函数是有效的(逻辑上,该函数仍然只有一次,因为它中的静态只存在一次,而不是单独存在于每个文件中或者只是在标题中声明它,但在一个 .cpp文件中定义它(但是,然后从中删除内联!)。

inline A& getA() { static A a; return a; }

使用new

可以规避销毁订单的潜在问题
inline A& getA() { static A *a = new A; return *a; }

然而,它的析构函数永远不会被调用。如果您需要线程安全,则应添加一个防止多次访问的互斥锁。 boost.thread可能有一些东西。

答案 4 :(得分:1)

  

在cpp文件中声明和定义

extern - ed声明保留在标题中。在实现文件中仅将定义为

你很亲密。使用命名空间代替全局变量。

namespace myns {
   int foo = 0;
}

现在,如果它是一个类对象,那么您正在查看Singletion模式。实际上,您的示例代码反映了Singleton设计。但是,如果要在标头中定义函数,请将其设置为内联 - 否则将导致ODR违规。

答案 5 :(得分:1)

它真的是一个全局变量,理论上可以被任何模块从外部访问,你应该将extern声明放在头文件中:

// MyClass.h
class MyClass { ... };
extern MyClass myGlobalInstance;

// MyClass.cpp
MyClass myGlobalInstance;

如果它只是一个真正只能由单个模块访问的全局对象,则通过将其作为私有(或受保护的)静态类变量,静态函数变量(如果只需要一个函数)来限制其作用域,或在匿名命名空间中:

选项1:

// MyClass.h
class MyClass
{
private:  // or protected, if you want it accessible by subclasses
    static MyClass myGlobalInstance;
};

选项2:

// MyClass.cpp
void someFunction()
{
    // it's global, but only accessible inside this function
    static MyClass myGlobalInstance;
    ...
}

选项3:

// MyClass.cpp
namespace
{
    MyClass myGlobalInstance;
}

// it's now only accessible in this file

答案 6 :(得分:0)

extern MyGlobalClass MyGlobalClassInstance;

修改:非静态>。<

答案 7 :(得分:-1)

为什么不使用好的旧单身模式?