关于c ++:静态类的未初始化静态数据成员


Uninitialized static data member of static class

我今天遇到了一个奇怪的问题,我不太明白。希望这里有人能帮忙。

设置相当简单。我有一个类,它有一个std::set类型的静态成员。该类有两个模板构造函数,它们只在参数数目上有所不同。这两个构造函数的行为相同,所以请注意,构造函数是模板化的,并且构造函数正在搜索并插入到std::set中。

我正在经历以下行为:对于类的静态实例,构造函数在静态std::set(find())上调用的第一个方法上崩溃。似乎该集未初始化。在我看来,在初始化静态成员变量之前调用了构造函数。

下面是一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
////////// Header File

class ConVar : public IListener
{
  friend EventHandler; // Event Handler auto registers all instances of convar to commands

public: // Auto

  template< typename T >
  ConVar(string const& name, string const& description, T const& default_value );

private:
  static std::set<u32> mRegisteredVars;
};


//////// INL file (included from header)

template< typename T >
ConVar::ConVar(string const& name, string const& description, T const& default_value )
  : mName(name),
    mhName(name),
    mDescription(description),
    mClamp(false)
 {
    u32 hname = CONSTHASH(name.c_str());
    ErrorIf(mRegisteredVars.find(hname) != mRegisteredVars.end(),"Attempt to create same ConVar multiple times. Note the ConVars are static singletons!");

    *this = default_value;

    mRegisteredVars.insert(hname);

    gCore.Events.Subscribe(mhName, this);
  }

   ///////////// .cpp file

  std::set<u32> ConVar::mRegisteredVars;

崩溃发生在find方法的errorif内部。如果我评论那行,它就会在插入的行上崩溃。

在main(类的静态实例)之前调用构造函数。有人知道这里会发生什么吗?


从构造函数访问彼此的全局对象在它们的声明顺序上会有问题。

有几种方法可以解决这个问题:

尝试

1
2
3
4
5
6
7
8
9
10
11
//Change
static std::set<u32> mRegisteredVars;

//Into
static std::set<u32>&  getRegisteredVarsSet()
{
    static  std::set<u32>&  mRegisteredVars;
    return mRegisteredVars;
}
// Obviously remove the `std::set<u32> ConVar::mRegisteredVars;`
// From the cpp file.

那么无论你在哪里使用:mRegisteredVars改为getRegisteredVarsSet()

现在,即使您从静态存储持续时间对象的构造函数访问mRegisteredVars,调用getRegisteredVarset()(以检索它)也将确保mrRegisteredVars在返回之前完全初始化,从而可供使用。

因为它是函数的静态成员,所以它的寿命是程序的长度,因此它将在调用之间保持其状态。


在调用main之前,不要访问静态/全局变量。这被称为"静态初始化顺序失败"。

你的mRegisteredVars在那一点上根本没有退出。做你所做的是未定义的行为。