Smart Pointer

 

인프런 Rookiss님의 'Part1: C++ 프로그래밍 입문' 강의를 기반으로 정리한 필기입니다. 
😎[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 강의 들으러 가기!

 

 


 

Dangling Pointer

 

더보기
#include <iostream>
using namespace std;
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <algorithm>

class Knight
{
public:
    Knight() { cout << "Knight 생성" << endl; }
    ~Knight() { cout << "Knight 소멸" << endl; }

    void Attack()
    {
        if (_target)
        {
            _target->_hp -= _damage;
            cout << "HP: " << _target->_hp << endl;
        }
    }

public:
    int _hp = 100;
    int _damage = 10;
    Knight* _target = nullptr;
};

int main()
{
    Knight* k1 = new Knight();
    Knight* k2 = new Knight();

    k1->_target = k2;

    delete k2; //k2를 지운다고 _target이 nullptr이 되는것은 아니다. 이것으로 인한 나비효과로 _target->_hp -= damage로 엉뚱한 메모리를 건드릴 수 있다.

    k1->Attack();


    return 0;
}

k2를 안전하게 삭제하는 방법

  • k2를 참조하고 있는 모든 _target를 nullptr로 밀어준다.
  • BUT, 이렇게 일일이 관리하기는 현실적으로 힘들다.

 

 

 


 

Smart Pointer - shared_ptr

 

shared_ptr

 

더보기
#include <iostream>
using namespace std;
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <algorithm>

class Knight
{
public:
    Knight() { cout << "Knight 생성" << endl; }
    ~Knight() { cout << "Knight 소멸" << endl; }

    void Attack()
    {
        if (_target)
        {
            _target->_hp -= _damage;
            cout << "HP: " << _target->_hp << endl;
        }
    }

public:
    int _hp = 100;
    int _damage = 10;
    Knight* _target = nullptr;
};

class RefCountBlock
{
public:
    int _refCount = 1;
};

template<typename T>
class SharedPtr
{
public:
    SharedPtr() { } //SharedPtr를 다음과 같이 깡통으로 만들면 기본적으로 nullptr이다.

    SharedPtr(T* ptr) : _ptr(ptr) 
    {
        if (_ptr != nullptr) //관리해야할 _ptr이 있다면
        {
            _block = new RefCountBlock(); //블락을 만들어준다.
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }

    SharedPtr(const SharedPtr& sptr) : _ptr(sptr._ptr), _block(sptr._block) //복사생성자
    {
        if (_ptr != nullptr)
        {
            _block->_refCount++;
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }

    void operator=(const SharedPtr& sptr)
    {
        _ptr = sptr._ptr;
        _block = sptr._block;

        if (_ptr != nullptr)
        {
            _block->_refCount++;
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }

    ~SharedPtr()
    {
        if (_ptr != nullptr)
        {
            _block->_refCount--;
            cout << "RefCount : " << _block->_refCount << endl;

            if (_block->_refCount == 0)
            {
                delete _ptr;
                delete _block;
                cout << "Delete Data" << endl;
            }
        }
    }

public:
    T* _ptr = nullptr;
    RefCountBlock* _block = nullptr;
};

int main()
{
    // 스마트 포인터 : 포인터를 알맞는 정책에 따라 관리하는 객체 (포인터를 래핑해서 사용)
    // shared _ptr, weak_ptr, unique_ptr
    SharedPtr<Knight> k2; //빈 상태

    {
        SharedPtr<Knight> k1(new Knight());
        k2 = k1; //빈 상태인 k2에 k1값을 복사하여 넣어준다. 복사대입연산자(void operator=) 사용.
    }
	//괄호가 끝나면 k1 소멸, BUT k1의 _refCount는 0이 아님.

    return 0;
}
//k2가 소멸되면서 메모리가 소멸된다. 이 때 k1 메모리도 삭제된다.

RefCountBlock

  • 참조 회수를 관리하는 블록
  • _refCount는 1부터 시작하여 만약 0이되면 기억하지 않아도되어 날려도 된다는 의미다.

 

 


 

 

Smart Pointer - unique_ptr

 

unique_ptr

더보기
#include <iostream>
using namespace std;
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <algorithm>

// smart pointer

class Knight
{
public:
    Knight() { cout << "Knight 생성" << endl; }
    ~Knight() { cout << "Knight 소멸" << endl; }

    void Attack()
    {
        if (_target.expired() == false)
        {
            shared_ptr<Knight> sptr = _target.lock();

            sptr->_hp -= _damage;
            cout << "HP: " << sptr->_hp << endl;
        }
    }

public:
    int _hp = 100;
    int _damage = 10;
    weak_ptr<Knight> _target;
};

class RefCountBlock
{
public:
    int _refCount = 1;
    int _weakCount = 1;
};

template<typename T>
class SharedPtr
{
public:
    SharedPtr() { }

    SharedPtr(T* ptr) : _ptr(ptr)
    {
        if (_ptr != nullptr)
        {
            _block = new RefCountBlock();
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }

    SharedPtr(const SharedPtr& sptr) : _ptr(sptr._ptr), _block(sptr._block)
    {
        if (_ptr != nullptr)
        {
            _block->_refCount++;
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }

    void operator=(const SharedPtr& sptr)
    {
        _ptr = sptr._ptr;
        _block = sptr._block;

        if (_ptr != nullptr)
        {
            _block->_refCount++;
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }

    ~SharedPtr()
    {
        if (_ptr != nullptr)
        {
            _block->_refCount--;
            cout << "RefCount : " << _block->_refCount << endl;

            if (_block->_refCount == 0)
            {
                delete _ptr;
                //delete _block;
                cout << "Delete Data" << endl;
            }
        }
    }

public:
    T* _ptr = nullptr;
    RefCountBlock* _block = nullptr;
};

int main()
{
    // 스마트 포인터 : 포인터를 알맞는 정책에 따라 관리하는 객체 (포인터를 래핑해서 사용)
    // shared _ptr, weak_ptr, unique_ptr
    
    shared_ptr<Knight> k1 = make_shared<Knight>();

    // k1 [   ]
    // k2 [   ]
    {
        shared_ptr<Knight> k2 = make_shared<Knight>();
        k1->_target = k2;
        k2->_target = k1;
    }
    k1->Attack();

    // unique_ptr : 일반적인 복사가 막힌 포인터
    unique_ptr<Knight> uptr = make_unique<Knight>();
    unique_ptr<Knight> uptr2 = std::move(uptr);

    return 0;
}

 

 

Shared _ptr

 

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
using namespace std;
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <algorithm>
 
// smart pointer
 
class Knight
{
public:
    Knight() { cout << "Knight 생성" << endl; }
    ~Knight() { cout << "Knight 소멸" << endl; }
 
    void Attack()
    {
        if (_target)
        {
            _target->_hp -= _damage;
            cout << "HP: " << _target->_hp << endl;
        }
    }
 
public:
    int _hp = 100;
    int _damage = 10;
    shared_ptr<Knight> _target = nullptr;
};
 
class RefCountBlock
{
public:
    int _refCount = 1;
};
 
template<typename T>
class SharedPtr
{
public:
    SharedPtr() { }
 
    SharedPtr(T* ptr) : _ptr(ptr)
    {
        if (_ptr != nullptr)
        {
            _block = new RefCountBlock();
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }
 
    SharedPtr(const SharedPtr& sptr) : _ptr(sptr._ptr), _block(sptr._block)
    {
        if (_ptr != nullptr)
        {
            _block->_refCount++;
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }
 
    void operator=(const SharedPtr& sptr)
    {
        _ptr = sptr._ptr;
        _block = sptr._block;
 
        if (_ptr != nullptr)
        {
            _block->_refCount++;
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }
 
    ~SharedPtr()
    {
        if (_ptr != nullptr)
        {
            _block->_refCount--;
            cout << "RefCount : " << _block->_refCount << endl;
 
            if (_block->_refCount == 0)
            {
                delete _ptr;
                delete _block;
                cout << "Delete Data" << endl;
            }
        }
    }
 
public:
    T* _ptr = nullptr;
    RefCountBlock* _block = nullptr;
};
 
int main()
{
    // 스마트 포인터 : 포인터를 알맞는 정책에 따라 관리하는 객체 (포인터를 래핑해서 사용)
    // shared _ptr, weak_ptr, unique_ptr
    
    shared_ptr<Knight> k1 = make_shared<Knight>();
 
    // k1 [   ]
    // k2 [   ]
    {
        shared_ptr<Knight> k2 = make_shared<Knight>();
        k1->_target = k2;
        k2->_target = k1;
    }
    k1->Attack();
 
 
    return 0;
}
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <iostream>
using namespace std;
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <algorithm>
 
// smart pointer
 
class Knight
{
public:
    Knight() { cout << "Knight 생성" << endl; }
    ~Knight() { cout << "Knight 소멸" << endl; }
 
    void Attack()
    {
        if (_target.expired() == false)
        {
            shared_ptr<Knight> sptr = _target.lock();
 
            sptr->_hp -= _damage;
            cout << "HP: " << sptr->_hp << endl;
        }
    }
 
public:
    int _hp = 100;
    int _damage = 10;
    weak_ptr<Knight> _target;
};
 
class RefCountBlock
{
public:
    int _refCount = 1;
    int _weakCount = 1;
};
 
template<typename T>
class SharedPtr
{
public:
    SharedPtr() { }
 
    SharedPtr(T* ptr) : _ptr(ptr)
    {
        if (_ptr != nullptr)
        {
            _block = new RefCountBlock();
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }
 
    SharedPtr(const SharedPtr& sptr) : _ptr(sptr._ptr), _block(sptr._block)
    {
        if (_ptr != nullptr)
        {
            _block->_refCount++;
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }
 
    void operator=(const SharedPtr& sptr)
    {
        _ptr = sptr._ptr;
        _block = sptr._block;
 
        if (_ptr != nullptr)
        {
            _block->_refCount++;
            cout << "RefCount : " << _block->_refCount << endl;
        }
    }
 
    ~SharedPtr()
    {
        if (_ptr != nullptr)
        {
            _block->_refCount--;
            cout << "RefCount : " << _block->_refCount << endl;
 
            if (_block->_refCount == 0)
            {
                delete _ptr;
                //delete _block;
                cout << "Delete Data" << endl;
            }
        }
    }
 
public:
    T* _ptr = nullptr;
    RefCountBlock* _block = nullptr;
};
 
int main()
{
    // 스마트 포인터 : 포인터를 알맞는 정책에 따라 관리하는 객체 (포인터를 래핑해서 사용)
    // shared _ptr, weak_ptr, unique_ptr
    
    shared_ptr<Knight> k1 = make_shared<Knight>();
 
    // k1 [   ]
    // k2 [   ]
    {
        shared_ptr<Knight> k2 = make_shared<Knight>();
        k1->_target = k2;
        k2->_target = k1;
    }
    k1->Attack();
 
    // unique_ptr : 일반적인 복사가 막힌 포인터
    unique_ptr<Knight> uptr = make_unique<Knight>();
    unique_ptr<Knight> uptr2 = std::move(uptr);
 
    return 0;
}
cs