我今天遇到了一个奇怪的问题,我并不完全理解。希望有人可以提供帮助。
设置相当简单。我有一个类有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之前调用(类的静态实例) 有谁知道这里会发生什么?
答案 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在返回之前将完全初始化,从而可供使用。
因为它是函数的静态成员,所以它的生命周期是程序的长度,因此它将在调用之间保持其状态。