1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/******************************************************************************
파일명   : Singleton.h
목적      : 싱글턴 패턴 생성
사용방식   : public 상속을 받아 사용
******************************************************************************/
#pragma once
 
template<class T>
class Singleton
{
private:
    static T* m_pInstatnce;
 
protected:
    Singleton(const Singleton&= delete;
    Singleton(const Singleton&&= delete;
    Singleton& operator = (const Singleton&= delete;
    Singleton& operator = (const Singleton&&= delete;
 
    Singleton()
    {
    }
    virtual ~Singleton()
    {
    }
 
public:
    /****************************************************************************
    함수명   : GetInstance
    설명      : T 클래스의 인스턴스 주소를 리턴받음
    *****************************************************************************/
    static T* GetInstance()
    {
        if (m_pInstatnce == nullptr)
        {
            m_pInstatnce = new T;
        }
 
        return m_pInstatnce;
    }
 
    /****************************************************************************
    함수명   : DestroyInstance
    설명      : 인스턴스를 지워줌
    *****************************************************************************/
    void DestroyInstance()
    {
        SAFE_DELETE(m_pInstatnce);
    }
};
 
//m_pInstatnce를 nullptr로 초기화
template<class T> T* Singleton<T>::m_pInstatnce = nullptr;
cs


이와 같은 Singleton 을 사용 할때 

1
2
3
4
5
6
7
8
9
10
 
class temp : public Singleton<temp> {
 
public:
    temp() {
 
    };
 
    int a = 3;
};
cs

요로코롬 상속 받아서 사용하고 있었다.


그런데 이렇게 template Singleton을 사용할 때의 문제점은


main(){

temp a;

}


이렇게 생성해도 아무런 오류가 나오지 않는다는 것이다.. 즉 여러 개 만들 수도 있다는 것.


하나의 객체만 가지고 싶어서 만드는 Singleton 이였는데... 뭔가 어긋나는 느낌이 든다.


그래서 


1
2
3
4
5
6
7
8
9
 
class temp : public Singleton<temp> {
 
        temp() {};
 
public:
 
    int a = 3;
};
cs


이렇게 생성자를 private로 바꿔서 만들게 되면 main 이나 다른 곳에서 temp를 만드는 것은 불가능하게 된다.


하지만..


1
2
3
4
if (m_pInstatnce == nullptr)
        {
            m_pInstatnce = new T;
        }
cs



그렇게 되면 이렇게 객체를 동적할당 할 때에 new에서 오류가 난다.


new 는 생성자를 부르기 때문에  private에 선언된 생성자를 부를 수 없기 때문에 오류가 난다.


그렇기 때문에 생성자를 호출하지 않는 malloc 을 사용한다면..


1
2
3
4
5
if (m_pInstance == NULL) {
            m_pInstance = (T*)malloc(sizeof(T));
//            m_pInstance = new T;
            memset(m_pInstance, NULLsizeof(*m_pInstance));
        }
cs



된다...


하지만 뭔가 만약에 T 객체내부에서 생성자와 같은 것으로 초기화 되기이전에 값을 넣었놨다면 그것마저 0으로 초기화가 되는 현상이 있었다.


때문에 Singleton은 

1
2
3
4
5
    if (m_pInstatnce == nullptr)
        {
            m_pInstatnce = new T;
        }
    
cs


그냥 이렇게 가져가고 상속 받는 클래스에서 friend로 Singleton을 보게해주자


1
2
3
4
5
6
7
8
9
10
11
12
13
14
class temp : public Singleton<temp> {
 
    friend Singleton;
    
    temp() {
 
    };
public:
//    void* operator new(std::size_t) = delete;
    
    int a = 3;
};
 
 
cs



그렇게 되니 무리가 없다... 끝!!



최종


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
template<class T>
class Singleton
{
private:
    static T* m_pInstatnce;
 
protected:
    Singleton(const Singleton&= delete;
    Singleton(const Singleton&&= delete;
    Singleton& operator = (const Singleton&= delete;
    Singleton& operator = (const Singleton&&= delete;
 
    Singleton()
    {
    }
    virtual ~Singleton()
    {
    }
 
public:
    /****************************************************************************
    함수명   : GetInstance
    설명      : T 클래스의 인스턴스 주소를 리턴받음
    *****************************************************************************/
    static T* GetInstance()
    {
        if (m_pInstatnce == nullptr)
        {
            m_pInstatnce = new T;
        }
 
        return m_pInstatnce;
    }
 
    /****************************************************************************
    함수명   : DestroyInstance
    설명      : 인스턴스를 지워줌
    *****************************************************************************/
    void DestroyInstance()
    {
        SAFE_DELETE(m_pInstatnce);
    }
};
 
//m_pInstatnce를 nullptr로 초기화
template<class T> T* Singleton<T>::m_pInstatnce = nullptr;


class temp : public Singleton<temp> {
 
    friend Singleton;
    
    temp() {
 
    };
public:
};
 
cs


static pointer에 new를 통해 동적할당하는 것이 ThreadSafe 할지 안할지 찾아봤었는데.


c++ 11 이후에서 부터는 굳이 정적변수초기화 앞뒤로 Lock 을 걸어주지 않아도 ThreadSafe 하다고 한다.


때문에 new는 별로 안전하지 않은 것 같다.. 


어차피 static 으로 선언한 변수는 여러번 선언해봤자 같은 메모리를 사용하므로 그냥


1
2
3
4
5
static T& getInstance()
    {
        static T instance;
        return instance;
    }
cs


이렇게 사용하는게 좋겠다.

+ Recent posts