본문 바로가기

WinAPI

[WinAPI] 게임 프레임워크 - 3. Reference Count

이 프로젝트에서 동적으로 할당된 메모리를 해제할 때는 SAFE_DELETE라는 매크로 함수를 사용한다.

 

#define SAFE_DELETE(p) if(p){delete p;p=NULL;}

 

포인터 p에 할당되어있는 메모리를 해제하고 p를 NULL로 지정한다. SAFE_DELETE를 사용하면 아무 이상 없어보이지만 문제는 동적 할당한 포인터를 여러 객체에서 참조하고 있을 때 나타난다. 

 

class Ref {
public:
	int value = 1;
};
class A {
	
public:
	Ref* r1;	
};
class B {
public:
	Ref* r2;	
};
int main()
{
	Ref* r = new Ref;
	
	A a;
	B b;
	a.r1 = r;
	b.r2 = r;
	
	cout << a.r1->value << '\n' << b.r2->value <<'\n';
	delete r;	
	cout << a.r1->value << '\n' << b.r2->value;

Ref 포인터를 참조하고 있는 클래스 A와 B는 동적으로 할당된 Ref가 해제되고 둘 다 쓰레기 값을 가진다. 그래서 프레임 워크에서 한 클래스에서 사용이 끝났다고 delete를 해버리면 다른 참조하고 있는 클래스에서 사용할 수 없어진다.

 

	void AddRef()
	{
		++m_iRef;
	}
	int Release()
	{
		--m_iRef;

		if (m_iRef == 0)
		{
			delete this;
			return 0;
		}
		return m_iRef;
	}

 

그래서 사용하는 것이 Reference Count이다. Ref 라는 클래스를 만들어 m_iRef 변수로 참조되는 횟수를 저장한다. 

Ref는 Object가 상속받아 이 Object가 몇번이나 참조되었는지 알 수 있다. 그래서 참조될 때 마다 AddRef를 하고 

사용이 끝난 후 Release를 한다. 그래서 참조횟수가 0이되면 delete로 메모리를 해제한다.

 

#define SAFE_RELEASE(p) if(p) {p->Release();p=NULL;}

 

매크로 함수 코드는 위와 같으며 Ref.h의 Release 함수를 사용해야 하므로 p는 Ref 클래스를 상속받아야 한다. 

 

	CPlayer* pPlayer = CObj::CreateObj<CPlayer>("Player", pLayer);
    
	SAFE_RELEASE(pPlayer);

 

위 코드는 InGameScene::Init 에서 플레이어를 생성하는 예시이다. CObj::CreateObj 템플릿으로 CPlayer 타입의 오브젝트를 생성하여 Layer가 가지고 있는 Object List에 추가하고, Object가 가지고 있는 static list에 한번 더 추가했다. 그래서 AddRef를 2번해서 pPlayer의 m_iRef는 3이 된다. m_iRef는 최초 생성시에 1이다. (생성한 것이 최초로 참조한 것과 같기 떄문에) 그리고 pPlayer을 Layer와 Object에 추가하는 것을 마쳤기 때문에 InGameScene에서는 사용할 일이 없으므로 SAFE_RELEASE 해준다. 그러면 pPlayer의 m_iRef는 2가 되고 NULL이 된다. Layer와 Object에 추가된 pPlayer은 NULL이 되지 않고 감소된 m_iRef만 적용된다.