프로그래밍/Modern c++

스마트 포인터

오늘의논리 2023. 3. 6. 22:37
728x90

스마트 포인터 : 포인터를 알맞은 정책에 따라 관리하는 객체( 포인터를 래핑해서 사용)

 

shared_ptr, weak_ptr, unique_ptr 이렇게 3가지가 있으며 

 

Shared_ptr 구현

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:


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()
{

	SharedPtr<Knight> k2;
	{
		SharedPtr<Knight> k1(new Knight());
		k2 = k1;
		
	}
	return 0;
}

이런식으로 구현되어 있다고 생각하면됨

 

그래서 shared_ptr 사용한다면

 

Knight 클래스에서 타켓을

 

shared_ptr<Knight> _target = nullptr;

 

해주고

int main()
{
	shared_ptr<Knight> k1 = make_shared<Knight>();

	{
		shared_ptr<Knight>k2 = make_shared<Knight>();
		k1->_target = k2;

	}

	k1->Attack();

	return 0;
}

이렇게 한다면 중괄호 밖을 나와도 k2 사라지지 않고 어택함수가 제대로 활용됨

 

Weak_ptr

shared_ptr<Knight>k1 = make_shared<Knight>();
shared_ptr<Knight>k2 = make_shared<Knight>();
k1->_target = k2;
k2->_target = k1;

이러한 상황에선 순환이 되서 메모리가 사라지지 않음 그렇기에 Weak_ptr 필요

using namespace std;


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<Knight>k1 = make_shared<Knight>();
	shared_ptr<Knight>k2 = make_shared<Knight>();
	k1->_target = k2;
	k2->_target = k1;
	
	k1->Attack();


	return 0;
}

 

Unique_ptr

나만 이세상에서 포인터를 가지고 있을거임 이라는 의미

unique_ptr<Knight> uptr = make_unique<Knight>();
unique_ptr<Knight> uptr2 = uptr; // 불가
unique_ptr<Knight> uptr2 = move(uptr); // 가능(이동론을 통해)
728x90