静态类的未初始化静态数据成员

时间:2011-10-15 01:00:40

标签: c++

我今天遇到了一个奇怪的问题,我并不完全理解。希望有人可以提供帮助。

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

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

这是一个简化的例子:

////////// 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之前调用(类的静态实例) 有谁知道这里会发生什么?

2 个答案:

答案 0 :(得分:3)

在调用main之前,不要访问静态/全局变量。这称为“Static Initialization Order Fiasco”。

您的mRegisteredVars根本就不会退出。做你做的是未定义的行为。

答案 1 :(得分:3)

从构造函数中相互访问的全局对象将会遇到其实例化顺序的问题。

有几种解决方法:

尝试

//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,调用getRegisteredVarsSet()(以检索它)也将保证mRegisteredVars在返回之前将完全初始化,从而可供使用。

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