静态变量未初始化 - 有时?

时间:2008-12-11 13:06:14

标签: c++

我有一个有谜题的游戏。使用拼图引擎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之前调用寄存器函数,但是在我们发现哈希没有哈希之前,所有东西都应该崩溃并烧掉。我们正在寻找的关键。

3 个答案:

答案 0 :(得分:2)

这可能是static initialization订单问题。尝试将其重写为“construct on first use”。

答案 1 :(得分:1)

如果链接器认为它不包含可访问的代码,则允许它完全删除编译单元。因此,如果.cpp文件中的所有函数都没有从其他地方显式调用,它可能会被完全丢弃,并且应该已经注册的对象在您的可执行文件中丢失了。

尝试在缺失的谜题的.cpp中放置一个虚拟外部函数,并从你的main()调用它来查看它是否能解决你的问题。

答案 2 :(得分:0)

看起来这毕竟与静态初始化无关 - 经过大量的日志记录后,我们发现一些不相关的代码正在摧毁指针,显然。