Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 编译器的惰性静态初始化。在c++;_C++_Static_Initialization_Lazy Evaluation - Fatal编程技术网

C++ 编译器的惰性静态初始化。在c++;

C++ 编译器的惰性静态初始化。在c++;,c++,static,initialization,lazy-evaluation,C++,Static,Initialization,Lazy Evaluation,我正试图实现一个带有注册器和测试器类实现的小型测试工厂,它们在程序启动时向工厂注册(从实际实现中删除了代码,因此可能无法编译;另外,请忽略TestFactory中getInstance的线程问题,删除了该代码以简化) 类基{ 公众: 虚拟int test()=0; 虚拟int createTestMsg()=0; }; 基本类型定义*(*pfn)(); 类测试工厂{ 公众: Base*getter(int类型){ auto iter=mtestregistry.find(类型); if(mtes

我正试图实现一个带有注册器和测试器类实现的小型测试工厂,它们在程序启动时向工厂注册(从实际实现中删除了代码,因此可能无法编译;另外,请忽略TestFactory中getInstance的线程问题,删除了该代码以简化)

类基{
公众:
虚拟int test()=0;
虚拟int createTestMsg()=0;
};
基本类型定义*(*pfn)();
类测试工厂{
公众:
Base*getter(int类型){
auto iter=mtestregistry.find(类型);
if(mtestregistry.end()!=iter){
返回iter->second();
}
返回NULL;
}
TestFactory*getInstance(){
静态TestFactory*ptr=newtestfactory();
分钟重置(ptr);
返回ptr;
}
私人:
静态std::映射注册表;
静态标准::唯一的ptr最小值;
};
班级登记员{
公众:
注册器(MessageTypes类型,pfnGetTester创建者){
TestFactory::getInstance()->registerType(类型,创建者);
}
};
//这是测试类实现
类测试:公共基{
私人:
静态注册器和注册器();
静态注册器和注册器;
};
//测试类cpp文件。
register&ToTest::mregistar=ToTest::registerMe();
注册商和测试商::注册商(){
静态注册器(int,
[]()->Base*{return new ToTest();});
报税注册主任;
}
问题是,在这种初始化方法中,编译器直到编译单元加载到内存中(第一次调用)时才创建mregistar对象。
有没有更好的方法来处理这种情况

据我所知,没有任何可靠的方法。该语言的定义使得静态范围对象的动态初始化可以在首次使用之前的任何时间发生。只有零和常量初始化保证在main之前发生。我认为它是C++14,规则稍微改变了一些,这样constexpr函数和构造函数就包含在其中了


我最近遇到了一个非常糟糕的初始化竞争条件(VS2010,静态初始值设定项不是线程安全的),最后我不得不使用这个原子双重检查锁方法来初始化变量。事实上,这是一个很难复制和发现的令人讨厌的小错误,我为此失去了工作——我甚至不知道我的最后一次尝试是否成功,也许永远也不会成功。如果您找到了一种方法来保证在某个已知点进行动态初始化,而不是在旋转线程之前确保在main(或者可能是DllMain或其他)中调用这些东西,那么我当然也想知道。除此之外,我将遵循一条规则,在11年前的机器翻译环境中永远不要使用静态变量,除非我有自杀倾向或其他原因。

为什么这是一个问题?我的意思是,在定义它们的文件加载之前,你不能使用这些注册,对吗?我想在程序启动时初始化这些静态变量,因此,这意味着我必须在这些测试对象注册到工厂之前调用它们,这不是正确的解决方案。也许您可以在main()的顶部创建一种伪方法来调用,该方法将在同一个.cpp文件中实现,并提前强制初始化?这是不可行的,因为这将是一个库,可能在其他项目中使用。您的库不会是第一个具有全局init函数的库。如果你能,我会避免,但如果你不能,至少你有好朋友。
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;
}