2014-10-14 4 views
0

나는 작은 시작 테스트 팩토리를 구현하려고 애 쓰고있다. 레지스트라와 테스터 클래스 구현은 프로그램 시작시 팩토리를 가지고 등록한다. (실제 구현에서 코드를 빼앗 았기 때문에 컴파일되지 않을 수도있다. TestFactory의 getInstance는 단순화하기 위해 해당 코드를 제거했습니다.).컴파일러에 의한 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 오브젝트를 생성하지 않는다는 점이다 (제 1이라고 함). 이 상황을 처리하는 더 좋은 방법이 있습니까?

+0

왜 문제입니까? 어쨌든 파일을 정의하는 파일이로드 될 때까지는 등록을 사용할 수 없다는 것을 의미합니까? –

+0

네, 맞습니다. –

+0

프로그램 시작시 이러한 정적 변수를 초기화하고 싶습니다. 즉,이 테스트 개체를 공장에 등록하기 전에 해당 테스트 개체를 호출해야한다는 것을 의미합니다. –

답변

1

내가 아는 신뢰할만한 방법이 없습니다. 언어는 정적 범위 객체의 동적 초기화가 처음 사용되기 전에 언제든지 발생할 수 있도록 정의됩니다. 메인이 나오기 전에 제로 및 상수 초기화 만 수행됩니다. 나는 C++ 14 규칙이 constexpr 함수와 생성자가 포함되도록 약간 변경되었다고 생각한다.

최근 (VS2010, 정적 이니셜 라이저는 스레드 안전하지 않음) 꽤 불쾌한 초기화 경쟁 조건에 부딪혔다. 변수를 초기화하는 데이 원자 복 확인 잠금 메서드를 사용해야했습니다. 실제로 그것을 번식하고 버그를 찾아내는 것은 짜증나게 작았습니다. 나의 마지막 시도가 효과가 있었는지 아마 알지도 못합니다. 어떤 알려진 지점에서 동적 초기화를 보장하는 방법을 찾지 못한다면 스레드를 회전하기 전에 메인 (또는 DllMain 또는 무엇이든)에서 이러한 것들 중 하나를 호출하기에 부족함을 확실히 알기를 바랍니다. 그보다는 내가 자살 같은 것이 아니면 뭔가 pre-11 몬태나 환경에서 정적 변수를 절대 사용하지 않을 규칙으로 가고 있습니다.

관련 문제