검색결과 리스트
글
웹서핑 조금만 해도 나오는 싱글턴 패턴 소스.
두번째 테스트로 상속을 받지 않고 싱글턴을 적용해 보았다.
class C : public CLmSingleton2<C> 로 선언 자체가 안된다. 소스를 보면 서로가 서로를 상속 받는 구조가 되어버린다.
평소처럼 사용하다가 싱글턴 클래스 상속과 싱글턴을 상속받은 부모 클래스를 다시 자식 클래스가
상속을 받아서 쓰는부분에 대해 궁금함이 생겼다.
일반적인 싱글턴 소스들
template< class T > class CLmSingleton { public: static T *getInstance() { if( !s_pInstance ) s_pInstance = new T(); return s_pInstance; } static void releaseInstance() { if( s_pInstance ) { delete s_pInstance; s_pInstance = NULL; } } protected: static T *s_pInstance; }; template< class T > T *CLmSingleton< T >::s_pInstance = 0;
//-------------------------------------------------------------- template< class T > class CLmSingleton2 : private T { public: static T* getInstance() { // if use in multi-thread env, should add lock here. static CLmSingleton2<t> s_Instance; return& s_Instance; } protected: CLmSingleton2() {} virtual ~CLmSingleton2() {} }; #define SINGLETON(p) CLmSingleton2<p>::getInstance()
상단에 있는 싱글턴 소스는
class A : public CLmSingleton<A> { public: A() {} virtual ~A() {} int a; }; A testClass; // 일반적인 정적 변수 선언이 가능. testClass.a = 99; // 이것은 단순히 testClass 라는 클래스 멤버변수의 값만 바뀐다. A* pA0 = testClass.getInstance(); // pA0의 멤버변수 a의 값은 쓰레기 값 A* pA1 = A::getInstance(); A* pA2 = CLmSingleton<A>::getInstance(); // pA0, pA1, pA2 세 포인터의 주소는 동일하다. pA2->a = 98; // pA0, pA1, pA2의 멤버변수 a가 전부 갱신됨.
testClass 와 포인터들은 다른 주소를 갖는다. 다만 testClass.getInstance() 로 불러오는 인스턴스만은 동일하다.
각각의 인스턴스는 동일하지만 ( testClass != 포인터 ) 이기 때문에 싱글턴이라 부르기 어렵다.
또한, 싱글턴의 특징 중 하나인 외부로 공개하지 않는 생성자와 소멸자가 public이다.
결국, 저 클래스는 실수로라도 정적 변수로 선언을 하게 된다면 나중에 문제가 커질 가능성이 있다.
혹시나 해서 생성자와 소멸자를 protected 와 private로 했는데, 생성자에 접근을 하지 못해 컴파일 에러가 뜬다.
class B { public: B() {} virtual ~B() {} int b; };
B* pb0 = B::getInstance(); // 상속을 받지 않았으므로 B에는 getInstance()란 메소드가 없어 오류
B* pb1 = CLmSingleton<B>::getInstance(); // B 클래스라는 새로운 인스턴스 생성 성공.
마지막 테스트는 상단 소스중 CLmSingleton2 로 했다.
class C { public: // protected 도 가능 C() {} virtual ~C() {} int c; };
두번째 싱글턴의 경우, 그 특징은 사용하려 명시한 클래스의 자식클래스로 상속이 된다. 첫번째는 싱글턴 자체가 부모클래스이고 사용하고 싶은 클래스는 자식클래스로 상속을 시키는 구조다.
이 싱글턴은 단지 아래 방법만이 가능하다.
C* pc0 = SINGLETON(C);
C* pc1 = SINGLETON(C);
두번째 싱글턴의 경우 클래스 생성자가 public이든 protected든 인스턴스가 생성이 된다. protected인데 생성이 되는 이유는 싱글턴이 부모의 생성/소멸자를 상속을 받았기에 내부에서는 부모를 참조할 수 있기 때문이다. private의 경우 생성/소멸자를 상속 시키지 않아 컴파일 에러가 난다.
//----------
그리고 두 싱글턴의 차이를 보자면 첫번재는 동적 인스턴스이다. 가져올때 없으면 new로 할당을 하고 존재한다면 이미 만들어진 인스턴스를 가져온다. 하지만 소멸자는 불리지 않아 인스턴스가 제대로 지워졌는지 확인이 안된다.
아니면 releaseInstance()를 호출하는 수 밖에 없다.
하지만 두번째 싱글턴은 정적 인스턴스이기 때문에 클래스 자체가 파괴가 되거나 프로그램이 종료가 된다면 메모리를 반환을 한다. 메모리 해제를 할 필요가 없다는 것이다.
그리고 첫번째 싱글턴처럼 인스턴스를 생성할 때 여러 방법이 불가능하다. 싱글턴 생성이나 인스턴스를 가져옴에 있어 통일성이 있다.
만약, 첫번째 싱글턴처럼 이렇게 만드나 저렇게 만드나 똑같은 인스턴스가 나온다면 인스턴스를 가져올 때 통일적이지 않아 나중가면 햇갈릴 가능성이 있는 것이다.
개인적으로 두번째 싱글턴이 좋다.
'Programming > 이런저런것들' 카테고리의 다른 글
유니코드 기반에서 콘솔 출력에 대한 문제. (0) | 2010.10.27 |
---|---|
3차원 배열? 헤딩과 삽질! (0) | 2010.05.25 |
PerformanceCounter 와 timeGetTime 과 Assembly count 비교 (0) | 2009.12.03 |
path 잡아줄때 은(는) 예상되지 않았습니다. 에러날때. (0) | 2009.12.03 |
std::map 에서 포인터를 선언된 녀석을 가져오는 법 (0) | 2009.10.30 |
RECENT COMMENT