由编译器进行的Lazy Static初始化。在c ++中

时间:2014-10-14 08:14:43

标签: c++ static initialization lazy-evaluation

我正在尝试使用注册器和测试器类实现来实现一个小型测试工厂,在程序启动时注册工厂(已经从实际实现中获取代码,因此可能无法编译;另外,请忽略getInstance的线程问题在TestFactory中,已经删除了该代码以简化。)。

class Base {
    public:
        virtual int test() = 0;
        virtual int createTestMsg() = 0 ;
};


typedef Base* (*pfn)();
class TestFactory {
    public:
        Base *getTester(int type) {
            auto iter = mTesterRegistry.find(type);
            if (mTesterRegistry.end() != iter) {
                return iter->second();
            }
            return NULL;
        }
        TestFactory * getInstance() {
           static TestFactory* ptr = new TestFactory();
           mInstance.reset(ptr);
           return ptr;
        }
    private:
        static std::map<int, pfn> mTesterRegistry;
        static std::unique_ptr<TestFactory> mInstance;
};

class Registrar {
    public:
        Registrar(MessageTypes type, pfnGetTester creator) {
            TestFactory::getInstance()->registerType(type, creator);
        }
};


// this is the test class implementation
class ToTest : public Base {
    private:
        static Registrar & registerMe();
        static Registrar & mRegistrar;
};


// test class cpp file.
Registrar &ToTest::mRegistrar = ToTest::registerMe();

Registrar & ToTest::registerMe() {
    static Registrar registrar(int, 
            []() -> Base * {return new ToTest();} );
    return registrar;
}

问题在于,在这种初始化方法中,编译器在编译单元加载到内存(首次调用)之前不会创建mRegistrar对象。 有没有更好的方法来处理这种情况?

1 个答案:

答案 0 :(得分:1)

我所知道的并不是任何可靠的方式。定义语言使得静态范围对象的动态初始化可以在第一次使用之前的任何时间发生。只有零和常量初始化才能保证在main之前发生。我认为C ++ 14的规则略有改变,因此constexpr函数和构造函数都包含在其中。

我最近遇到了一个非常讨厌的初始化竞争条件(VS2010,静态初始化器不是线程安全的)我最终不得不使用这种原子双重检查锁定方法来初始化变量。事实上,这是一个令人烦恼的小难以重现和发现我失去工作的错误 - 我甚至不知道我的最后一次尝试是否有效,而且可能永远不会。如果你找到一种方法来保证动态初始化在一些已知的点上,确保在旋转线程之前在main(或者可能是DllMain或其他)中调用任何这些东西,我当然也想知道。除此之外我还没有在11级之前的MT环境中使用静态变量,除非我有自杀倾向或什么。