MMOServer

RefCount(C++)

이야기prog 2025. 3. 21. 22:33
#pragma once
class RefCountable
{
public:
	RefCountable(): _refCount(1) {}
	virtual ~RefCountable() { std::cout << "die!" << endl; }

	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=(const TSharedPtr&& rhs) noexcept {
		Release();
		_ptr = rhs._ptr;

		return *this;
	}

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

	T& operator*() { return *_ptr; } // (*name).func
	const T& operator*() const{ return *_ptr; } // const 객체 -> const 멤버함수만 가능
	operator T*() const { return _ptr; } // name* tmp = (name*)obj
	T* operator->() { return _ptr; }
	const T* operator->() const { return _ptr; }

	operator T&() const{ return *_ptr; }
	operator T() 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) {
			_ptr->ReleaseRef();
			_ptr = nullptr;
		}
	}
private:
	T* _ptr = nullptr;
};

스마트 포인터느낌으로 구현한 것이다.

 

class Wraith : public RefCountable {
public:
	int _hp = 150;
	int _posX = 0;
	int _posY = 0;
};
using WraithRef = TSharedPtr<Wraith>;
class Missile : public RefCountable {
public:

	Missile& operator=(const Missile& rhs) {
		*this = rhs;
		return *this;
	}
	void SetTarget(WraithRef 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;
	}
	Wraith* _target = nullptr;
};

using MissileRef = TSharedPtr<Missile>;
int main() {

	WraithRef wraith(new Wraith());
	wraith->ReleaseRef();
	MissileRef missile(new Missile());
	missile->ReleaseRef();
	
	missile->SetTarget(wraith);
	wraith->_hp = 0;
	wraith = nullptr; // nullptr은 자동으로 형변환하기 떄문에
					  // wraith
	while (true) {

		if (missile) {
			
			missile->Update();
		}

		if (!wraith)
			break;
	}

	missile = nullptr;
	return 0;
}

wraith = nullptr 부분에서 WraithRef(nullptr)이 생성되고 복사 대입 연산자 혹은 이동 대입 연산자가 호출된다.

'MMOServer' 카테고리의 다른 글

메모리 관련  (0) 2025.03.27
Smart_Pointer(C++)  (0) 2025.03.22
DeadLock 탐지(C++)  (0) 2025.03.20
Read-Write Lock(C++)  (0) 2025.03.19
멀티스레드의 메모리 이슈  (0) 2025.03.13