싱글턴 클래스를 상속받아서 싱글턴으로 만들어 버리는 소스가 있길레 슬쩍 해 보았습니다.
문제는, 분석이 지금 잘 안되고 있는데요.
일단 소스 날려 봅니다.
#include <Windows.h>
#include <iostream>
#include <assert.h>
using namespace std;
template <typename T>
class ZSingleton
{
private:
static T* ms_pSingleton;
public:
ZSingleton() {
assert(NULL == ZSingleton<T>::ms_pSingleton );
ZSingleton<T>::ms_pSingleton = (T*)this;
}
~ZSingleton() {
ZSingleton<T>::ms_pSingleton = NULL;
cout << "소멸하니?";
}
static T* GetSingleton() {
return ms_pSingleton;
}
};
template <typename T>
T* ZSingleton<T>::ms_pSingleton = NULL;
이러한 클래스가 있을경우.
class ZShape : public ZSingleton<ZShape>
{
public:
void Out() { cout << "거시기" << endl; }
}
이럴 경우
void main()
{
ZSingleton::GetSingleton()->Out();
}
로 "거시기"를 출력할 수 있습니다.
일단 제가 생각한 분석 내용입니다. (과거에 제가 사용했던 싱글턴은 메모리를 할당하고 직접 해지해 주는 과정을 필요로 했었는데 이것은 아니더군요)
static으로 생성할 클래스의 포인터를 가지고 있는 객체가 있습니다. static은 정적이며 실행과 동시에 메모리에 상주하게 됩니다.
일단 생성자는 ms_pSingleton이 NULL인지 검사를 합니다. NULL이 아닐경우 오류가 발생하며 싱글턴이 아님을 알게 되어 프로그램이 종료되어 버립니다.
만약 오류가 발생하지 않았다면 this로써 ms_pSingleton에 만들어진 객체의 시작 주소를 저장하게 됩니다.
(따라서 따로 메모리를 할당해야 하는 점이 없게 됩니다. 클래스가 상주하는 첫 주소를 가지고 있기 때문이지요)
GetSingleton을 하면 생성된 클래스의 첫 주소를 가지고 있기 때문에 그 클래스의 함수를 호출할 수가 있습니다. 그리고 정적으로 존재하고 따로 메모리 할당을 하지 않았기 때문에
메모리 해지는 필요가 없어지게 됩니다.
...이상이 제가 분석한 것인데.
이게 맞는지 모르겠습니다.
바로, static으로 선언하면 메모리에 항상 크기를 가지고 있게 되며 처음 클래스의 주소를 대입했으니 메모리 할당이 필요없다는 것..
말이죠.(new나 delete가 불필요 한 것이 정확히 이 이유 때문인지 확신이 서지 않습니다)
그리고 KSingleton의 생성자와 소멸자가 불리는 시점이 궁금합니다. 디버깅 모드로 브레이크를 걸어봐도 그 쪽은 무시해버리더군요.
그럼 가르침 부탁드리겠습니다. 좋은 밤 되십시오-ㅅ-
3D에 즐거워하고 있는 그럭저럭 초보인 랩좀비군이었습니다.
메모리를 할당하는 부분이 아무곳에도 없기때문에 제가 보기에는 작동하지 제대로 않을것 같습니다.
현재 테스트코드에서 쓰인 Out();는 어떠한 멤버변수에도 접근을 하지않기 때문에 메모리가 할당되지 않더라도 다행히 뻑이나지 않는 구조로 보입니다.
void Out() { cout << m_iZShapeSize << endl; }
이런식으로 멤버변수 하나 추가해서 테스트해보세요...바로 뻑날겁니다.
static이라 하더라도 포인터를 static으로 할당한것이지 인스턴스를 static으로 할당한것이 아니므로
아무런 생성/소멸이 일어나지 않았기 때문에 생성자/소멸자가 전혀 호출되지 않는 것입니다.
아시다시피 전역변수와 비교했을때 싱글톤의 장점중의 하나는 생성/소멸시점을 제어할수 있다는 것입니다.
전역변수는 프로그래머가 생성/소멸을 제어할수 없기 때문에 싱글톤간의 생성/소멸 순서가 중요해지는 경우 프로그램의 흐름을 제어할수가 없습니다..~
때문에 별도의 Initialize(), Release() 함수를 두고, 생성자/소멸자에서는 아무런 일을 안하는 형태로 만들어서 제어하기도 합니다.
( 대부분 싱글톤의 경우도 이런 함수를 소유하기때문에 특별한 장점이 아니다 라고 하기도 합니다만...^^ )
다른곳에서 생성하는 코드가 있거나 아니면..
class ZShape : public ZSingleton<ZShape>
{
.................
}ZInstance;
이런식으로 선언과 동시에 전역변수를 하나 생성하는 형태가 아닐까 추측해봅니다...
( 이 경우 전역변수와 다를바 없기때문에 생성/소멸 시점을 제어할수가 없습니다. )