[C++] smart pointer
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 | 
'⭐ Programming > C++' 카테고리의 다른 글
| callback 함수 (0) | 2023.09.18 | 
|---|---|
| [C++]L-value와 R-value, R-value reference (0) | 2022.04.24 | 
| [C++] 콜백 함수 (Callback function) (0) | 2022.04.17 | 
| [C++] 템플릿(Template) 2: 클래스 템플릿 (0) | 2022.04.17 | 
| [C++] 템플릿(Template) 1: 함수 템플릿 (0) | 2022.04.16 | 
댓글
이 글 공유하기
다른 글
- 
callback 함수
callback 함수
2023.09.18 - 
[C++]L-value와 R-value, R-value reference
[C++]L-value와 R-value, R-value reference
2022.04.24 - 
[C++] 콜백 함수 (Callback function)
[C++] 콜백 함수 (Callback function)
2022.04.17 - 
[C++] 템플릿(Template) 2: 클래스 템플릿
[C++] 템플릿(Template) 2: 클래스 템플릿
2022.04.17