我有一个有谜题的游戏。使用拼图引擎ID从脚本文件创建拼图。 Puzzle引擎使用静态哈希中的静态变量注册自己。我有关于崩溃的报告,我们已经将问题跟踪到没有某些密钥的哈希,这些密钥应该由静态函数添加。
请注意,这是我们无法重现的错误,也就是说,该方法通常有效。事实上,我不知道为什么有时它显然没有。是否有可能不调用这些静态函数?也许是编译器错误? (Visual C ++ 2005)
拼图工厂类型
class PuzzleMode;
typedef PuzzleMode* (*fnPuzzleFactory)(bool* bVictory, const char* sPuzzleCode, const GFC::StringList& lParams);
引擎使用此宏来确保它们已注册。有一个静态bool,它作为注册工厂并返回true的函数的结果初始化:
#define REGISTER_PUZZLE(CODE, CLASSNAME) \
PuzzleMode* puzzleFactory##CLASSNAME (bool* bVictory, const char* sCode, const StringList& lParams) \
{ \
return new CLASSNAME(bVictory, sCode, lParams); \
} \
\
static bool registerPuzzle##CLASSNAME (void) \
{ \
PuzzleMode::registerPuzzleFactory(CODE, puzzleFactory##CLASSNAME); \
return true; \
} \
\
static bool s_bRegisteredPuzzle##CLASSNAME = registerPuzzle##CLASSNAME();
示例,在拼图引擎.cpp中:
REGISTER_PUZZLE("bloodcollection", BloodCollection);
其他地方,在.cpp:
static Hash<String, fnPuzzleFactory>* s_hPuzzleFactories = NULL;
void PuzzleMode::registerPuzzleFactory (const char* sId, fnPuzzleFactory pFactory)
{
if (!s_hPuzzleFactories)
s_hPuzzleFactories = new Hash<String, fnPuzzleFactory>();
String sLowId = String(sId).lower();
s_hPuzzleFactories->setAt(sLowId, pFactory);
}
所有这一切都应该在应用程序启动时发生。很久以后它就像这样使用了
PuzzleMode* PuzzleMode::createPuzzleInstance (const char* sEngine, bool* bVictory, const GFC::StringList& lParams)
{
// Shouldn't happen
if (!s_hPuzzleFactories)
s_hPuzzleFactories = new Hash<String, fnPuzzleFactory>();
String sLowId = String(sEngine).lower();
if (!s_hPuzzleFactories->hasKey(sLowId)) // <----- HERE
return NULL;
fnPuzzleFactory fnFactory = s_hPuzzleFactories->getAt(sLowId);
return fnFactory(bVictory, sEngine, lParams);
}
有时,但有时候,在上面标记的行中,哈希没有密钥。
有什么想法吗?我能想到的唯一一件事(我在写这篇文章的时候就想到了)是在将哈希本身初始化为NULL之前调用寄存器函数,但是在我们发现哈希没有哈希之前,所有东西都应该崩溃并烧掉。我们正在寻找的关键。
答案 0 :(得分:2)
这可能是static initialization订单问题。尝试将其重写为“construct on first use”。
答案 1 :(得分:1)
如果链接器认为它不包含可访问的代码,则允许它完全删除编译单元。因此,如果.cpp文件中的所有函数都没有从其他地方显式调用,它可能会被完全丢弃,并且应该已经注册的对象在您的可执行文件中丢失了。
尝试在缺失的谜题的.cpp中放置一个虚拟外部函数,并从你的main()调用它来查看它是否能解决你的问题。
答案 2 :(得分:0)
看起来这毕竟与静态初始化无关 - 经过大量的日志记录后,我们发现一些不相关的代码正在摧毁指针,显然。