Reference Counting

์›๋ž˜๋ฒŒ๋ ˆยท2022๋…„ 8์›” 1์ผ
0

๐ŸŒž ์Šค๋งˆํŠธํฌ์ธํ„ฐ์˜ ํ•„์š”์„ฑ : ํ‹€๋ฆฐ์˜ˆ์‹œ

์Šคํƒ€ํฌ๋ž˜ํ”„ํŠธ์—์„œ ๋ ˆ์ด์Šค๋ผ๋Š” ์œ ๋‹›์ด ๋‹ค๋ฅธ ํƒ€๊ฒŸ์„ ๊ณต๊ฒฉํ•˜๋Š” ์˜ˆ์‹œ

class Wraight
{
public : 
	int _hp = 150;
	int _posX = 0;
	int _posY = 0;
};

class Missile
{
public :
	void SetTarget(Wraight* target)
	{
		_target = target;
	}

	void Update() 
	{
		int posX = _target->_posX;
		int posY = _target->_posY;
	}
	
	
	Wraight* _target = nullptr;

};


int main()
{
	Wraight* wraight = new Wraight();
	Missile* missile = new Missile();
	missile->SetTarget(wraight);


	wraight->_hp = 0;
	delete wraight;

	while (true) 
	{
		if (missile) 
		{
			missile->Update();
		}
	}
	delete missile;
}

๋ ˆ์ด์Šค์˜ ๋ฏธ์‚ฌ์ผ์ด ํƒ€๊ฒŸ์„ ๋”ฐ๋ผ๊ฐ€๊ฒŒ๋” ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค.
๋งŒ์•ฝ์— ๋ ˆ์ด์Šค๊ฐ€ ํ”ผ๊ฒฉ์„ ๋‹นํ•˜์—ฌ ๋ ˆ์ด์Šค๊ฐ€ delete๊ฐ€ ๋์Šต๋‹ˆ๋‹ค.
์ด ๊ฒฝ์šฐ ๋ ˆ์ด์Šค ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฏธ์‚ฌ์ผ ๊ฐ์ฒด๋Š” null๊ฐ’์„ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค.
์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์ƒ๊ฐํ•˜์ง€ ์•Š๊ณ , ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์žˆ์Œ์—๋„ delete๋ฅผ ํ•ด์ค€ ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ๋๋‹ค.


๐ŸŒž ํ•ด๊ฒฐ๋ฐฉ๋ฒ• : Reference Counting

  • ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด์˜ ๊ฐฏ์ˆ˜๋ฅผ ์„ธ๋Š” ๋ฉ”๋ชจ๋ฆฌ๊ด€๋ฆฌ ๋ฐฉ๋ฒ•์ด๋‹ค.

RefCounting.h

#pragma once
/*--------------
	RefCountable
---------------*/


class RefCountable
{
public:
	RefCountable() : _refCount(1) { }
	virtual ~RefCountable() { }

	int32 GetRefCount() { return _refCount; }
	
	int32 AddRef() { return ++_refCount; }
	int32 ReleaseRef()
	{
		int32 refCount = --_refCount;
		if (refCount == 0) {
			delete(this);
		}
		return refCount;
	}
protected:
	int32 _refCount;
};

Main

#include "RefCounting.h"

class Wraight : public RefCountable
{
public : 
	int _hp = 150;
	int _posX = 0;
	int _posY = 0;
};

class Missile : public RefCountable
{
public :
	void SetTarget(Wraight* target)
	{
		_target = target;
		target->AddRef();
	}

	void Update() 
	{
		if (_target == nullptr) return;
		int posX = _target->_posX;
		int posY = _target->_posY;
		
		if (_target->_hp == 0)
		{
			_target->ReleaseRef();
			_target = nullptr;
		}
	}
	
	Wraight* _target = nullptr;

};


int main()
{
	Wraight* wraight = new Wraight();
	Missile* missile = new Missile();
	missile->SetTarget(wraight);

	
	wraight->_hp = 0;
	wraight->ReleaseRef();
	while (true) 
	{
		if (missile) 
		{
			missile->Update();
		}
	}
	missile->ReleaseRef();
}

๐ŸŒž ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ์˜ Reference Counting์˜ ๋ฌธ์ œ

์œ„์˜ ์ฝ”๋“œ๋Š” ํ˜„์žฌ _refCount์˜ ๊ฐ’์ด atomicํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— atomic์œผ๋กœ _refCount๋ฅผ ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ๋งŒ ํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์ง€๋งŒ ์•ˆ๋œ๋‹ค.

๊ทธ ์ด์œ ๋Š” _refCount์˜ add ๋˜๋Š” releaseํ•˜๋Š” ์ผ์ด atomicํ•˜๊ฒŒ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ด๋ ‡๋“ฏ ์ˆ˜๋™์œผ๋กœ add, release๋ฅผ ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๊ณ , ์Šค๋งˆํŠธํฌ์ธํ„ฐ๋ฅผ ์ด์šฉํ•ด์„œ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์ด ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œํ™˜๊ฒฝ์—์„œ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.


๐ŸŒž ์Šค๋งˆํŠธํฌ์ธํ„ฐ : SharedPtr

  • refCounting ๊ฐ์ฒด๋ฅผ ๋žฉํ•‘ํ•˜์—ฌ ํฌ์ธํ„ฐ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์ฝ”๋“œ ์ƒ์—์„œ ์ง์ ‘์ ์œผ๋กœ(์ˆ˜๋™์ ์œผ๋กœ) add, release๋ฅผ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ SharedPtr์—์„œ ์ž๋™์ ์œผ๋กœ(null์ด ๋˜๋ฉด) ํ•ด์ฃผ๊ฒŒ๋” ํ•˜๋Š” ๊ฒƒ์ด ์ปจ์…‰์ด๋‹ค.
RefCounting.h

#pragma once
/*--------------
	RefCountable
---------------*/


class RefCountable
{
public:
	RefCountable() : _refCount(1) { }
	virtual ~RefCountable() { }

	int32 GetRefCount() { return _refCount; }
	
	int32 AddRef() { return ++_refCount; }
	int32 ReleaseRef()
	{
		int32 refCount = --_refCount;
		if (refCount == 0) {
			delete this;
		}
		return refCount;
	}
protected:
	atomic<int32> _refCount;
};





template<typename T>
class TSharedPtr
{
public:
	TSharedPtr() { }
	TSharedPtr(T* ptr) { Set(ptr); }
	//๋ณต์‚ฌ
	TSharedPtr(const TSharedPtr& rhs) { Set(rhs._ptr); }
	//์ด๋™
	TSharedPtr(TSharedPtr&& rhs)
	{
		_ptr = rhs._ptr;
		rhs._ptr = nullptr;
	}
	//์ƒ์† ๊ด€๊ณ„ ๋ณต์‚ฌ
	template<typename U>
	TSharedPtr(const TSharedPtr<U>& rhs) { Set(static_cast<T*>(rhs._ptr)); }

	~TSharedPtr() { Release(); }

public:
	//๋ณต์‚ฌ ์—ฐ์‚ฐ์ž
	TSharedPtr& operator=(const TSharedPtr& rhs)
	{
		if (_ptr != rhs._ptr)
		{
			Release();
			Set(rhs._ptr);
		}
		return *this;
	}
	//์ด๋™ ์—ฐ์‚ฐ์ž
	TSharedPtr& operator=(TSharedPtr&& rhs)
	{
		Release();
		_ptr = rhs._ptr;
		rhs._ptr = nullptr;
		return *this;
	}

	bool		operator==(const TSharedPtr& rhs) const { return _ptr == rhs._ptr; }
	bool		operator==(T* ptr) const { return _ptr == ptr; }
	bool		operator!=(const TSharedPtr& rhs) const { return _ptr != rhs._ptr; }
	bool		operator!=(T* ptr) const { return _ptr != ptr; }
	bool		operator<(const TSharedPtr& rhs) const { return _ptr < rhs._ptr; }
	T*			operator*() const { return _ptr; }
	const T*	operator*() const { return _ptr; }
				operator T* () const { return _ptr; }
	T*			operator->() { return _ptr; }
	const T*	operator->() const { return _ptr; }

	bool isNull() { return _ptr == nullptr; }

private:
	inline void Set(T* ptr)
	{
		_ptr = ptr;
		if (ptr)
			ptr->AddRef();

	}

	inline void Release()
	{
		if (_ptr != nullptr) 
		{
			_ptr->ReleaseRef();
			_ptr = nullptr;
		}
		
	}


private:
	T* _ptr = nullptr;
};

Main

#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <atomic>
#include <mutex>
#include <windows.h>
#include <future>
#include "ThreadManager.h"

#include "RefCounting.h"

class Wraight : public RefCountable
{
public:
	int _hp = 150;
	int _posX = 0;
	int _posY = 0;
};

using WraightRef = TSharedPtr<Wraight>;

class Missile : public RefCountable
{
public:
	void SetTarget(WraightRef target)
	{
		_target = target;
		// ์ค‘๊ฐ„์— ๊ฐœ์ž… ๊ฐ€๋Šฅ
		//target->AddRef();
	}

	bool Update()
	{
		if (_target == nullptr)
			return true;

		int posX = _target->_posX;
		int posY = _target->_posY;

		// TODO : ์ซ“์•„๊ฐ„๋‹ค

		if (_target->_hp == 0)
		{
			//_target->ReleaseRef();
			_target = nullptr;
			return true;
		}

		return false;
	}

	WraightRef _target = nullptr;
};

using MissileRef = TSharedPtr<Missile>;

int main()
{
	WraightRef wraight(new Wraight());
	wraight->ReleaseRef();
	MissileRef missile(new Missile());
	missile->ReleaseRef();

	missile->SetTarget(wraight);

	// ๋ ˆ์ด์Šค๊ฐ€ ํ”ผ๊ฒฉ ๋‹นํ•จ
	wraight->_hp = 0;
	//delete wraight;
	//wraight->ReleaseRef();
	wraight = nullptr;

	while (true)
	{
		if (missile)
		{
			if (missile->Update())
			{
				//missile->ReleaseRef();
				missile = nullptr;
			}
		}
	}

	//missile->ReleaseRef();
	missile = nullptr;
	//delete missile;
}

profile
ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ๋‹ด์€ ๋ธ”๋กœ๊ทธ ์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€