2014-10-14 3 views
0

Я пытаюсь реализовать небольшую фабрику испытаний с реализацией класса регистратора и тестера, которые регистрируются на фабрике при запуске программы (они взяли код из фактической реализации, поэтому могут не компилироваться, а также игнорировать проблемы потоков для getInstance в TestFactory, удалили этот код, чтобы упростить.).Lazy Static инициализация компилятором. в C++

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 до времени загружается модуль компиляции в памяти (первый называется). Есть ли лучший способ справиться с этой ситуацией?

+0

Почему это проблема? Я имею в виду, что вы не можете использовать регистрацию, пока файл, определяющий их, не будет загружен в любом случае, не так ли? –

+0

Да, это правда. –

+0

Я хочу инициализировать эти статические переменные при запуске программы, поэтому это означает, что я должен сделать вызов этим тестовым объектам, прежде чем они будут зарегистрированы на заводе, это неправильное решение. –

ответ

1

На самом деле нет надежного способа, которым я знаю. Язык определен таким образом, что динамическая инициализация объектов статической области видимости может произойти в любое время до первого использования. До основной будет гарантирована только нулевая и постоянная инициализация. Я думаю, что C++ 14 правила немного изменены, так что в него включены функции constexpr и конструкторы.

В последнее время я столкнулся с довольно неприятным состоянием гонки инициализации (VS2010, статические инициализаторы не являются потокобезопасными), и мне пришлось перейти с этим методом блокировки атомарного двойного контроля для инициализации переменной. На самом деле это было настолько раздражающе трудно воспроизвести и найти ошибку, что я потерял свою работу над ней - я даже не знаю, работала ли моя последняя попытка и, вероятно, никогда не будет. Если вы найдете способ гарантировать динамическую инициализацию в какой-то известной точке, не дожидаясь вызова любой из этих вещей в главном (или, возможно, DllMain или что-то еще), перед прямыми потоками, я бы тоже хотел узнать. Короче, я собираюсь с правилом никогда не использовать статические переменные в среде до 11 МТ, если я не самоубийственна или что-то еще.

Смежные вопросы