C++ 静态类的未初始化静态数据成员
我今天遇到了一个奇怪的问题,我真的没有完全理解。希望这里有人能帮忙 设置相当简单。我有一个类,它有一个std::set类型的静态成员。该类有2个模板构造函数,它们仅在参数数量上有所不同。这两个构造函数的行为相同,所以只需注意构造函数是模板化的,并且构造函数正在搜索并插入std::set 我正在经历以下行为: 对于类的静态实例,构造函数在静态std::set(find())上调用的第一个方法上崩溃。看起来该集合未初始化。在我看来,构造函数是在静态成员变量初始化之前被调用的 以下是一个简化的示例:C++ 静态类的未初始化静态数据成员,c++,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;
//头文件
类别ConVar:公共图书馆
{
friend EventHandler;//事件处理程序自动将convar的所有实例注册到命令
public://Auto
模板
ConVar(字符串常量和名称、字符串常量和描述、T常量和默认值);
私人:
静态标准::设置mRegisteredVars;
};
////////INL文件(包含在标题中)
模板
ConVar::ConVar(字符串常量和名称、字符串常量和描述、T常量和默认值)
:mName(名称),
mhName(姓名),
M说明(说明),
mClamp(假)
{
u32 hname=CONSTHASH(name.c_str());
ErrorIf(mRegisteredVars.find(hname)!=mRegisteredVars.end(),“尝试多次创建同一个ConVar。注意,ConVar是静态单例!”;
*这=默认值;
mRegisteredVars.insert(hname);
gCore.Events.Subscribe(mhName,this);
}
/////////////.cpp文件
std::set ConVar::mRegisteredVars;
崩溃发生在find方法的ErrorIf内部。如果我对该行进行注释,它会在插入的行上崩溃
构造函数在main之前调用(类的静态实例)
有人知道这里发生了什么吗?在调用
main
之前,不要访问静态/全局变量。这被称为“”
您的
mRegisteredVars
根本不会在该点退出。执行您所做的操作是未定义的行为。从构造函数中相互访问的全局对象的实例化顺序将出现问题
有两种方法可以解决这个问题:
试一试
//更改
静态标准::设置mRegisteredVars;
//进入
静态std::set&getRegisteredvarset()
{
静态标准::设置和注册变量;
返回mRegisteredVars;
}
//显然,删除'std::set ConVar::mRegisteredVars`
//从cpp文件。
然后,无论您在哪里使用:mRegisteredVars
更改为getRegisteredvarset()
现在,即使您从静态存储持续时间对象的构造函数访问mRegisteredVars
,调用getRegisteredvarset()(检索它)也将保证mRegisteredVars在返回之前完全初始化,因此可以使用
因为它是函数的静态成员,它的生命周期是程序的长度,因此它将在调用之间保持其状态。我们需要一个完全运行的示例来展示该行为,否则我们只是猜测。但是,听起来您遇到了初始化问题的全局顺序。您是否正在全局范围内创建类型为
ConVar
的对象?感谢您指出这一点。我没有意识到这一点,我几乎可以肯定编译器会在访问构造函数之前识别并初始化静态成员,即使类本身是静态的。
//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.