2021 시작

세상의 모든 자원은 힙에서만 생기지 않는다. 그리고 힙에서 생기지 않은 자원은 스마트포인터로 처리하지 않는 게 일반적인 견해이다. 항상 그런 것만은 아니지만 우리가 직접 자원관리 클래스를 만들어야 할 때가 있다. 예시를 봐보자

 

뮤텍스 잠금을 관리하는 클래스를 하나 만들고 싶은데 이전에 걸어놓은 뮤텍스를 잊지 않고 풀어주기 위해서 이 코드를작성했다고치자

class Lock 
{
public:
	explicit Lock(Mutex* pm)
		: mutexPtr(pm)
	{
		lock(mutexPtr);				//자원을 획득한다.
	}
	~Lock() { unlock(mutexPtr); }	//자원을 해제한다.

	void lock(Mutex* pm) {}
	void unlock(Mutex* pm) {}

private:
	Mutex* mutexPtr;
};


Mutex m;				//쓰고 싶은 뮤텍스를 정의한다.
...
{						//임계 영역을 정하기 위해 블록을 만든다.
	Lock m1(&m);		//뮤텍스에 잠금을 건다.
	.....;				//임계영역에서 할 연산을 수행한다.
						
}						//자동으로 풀린다.

 

여기까지만 보면 앞으로도 잘 될 것 같은데 Lock객체가 복사된다면 어떻게 해야 할까? 아니 복사하려는 움직임을 보이면 어떻게 처리해야 할까?

크게 4가지가 있지만 대표적인 2가지만 알아보겠다.

 

1. 복사를 금지한다.

그냥 복사 생성자와 대입 연산자에 delete를 걸어버려서 금지시켜라

 

2. 관리하고 있는 자원에 대해 참조 카운팅을 수행한다.

shared_ptr을 사용하라는데 shared_ptr은 사용 후 가리키고 있는 대상을 삭제해버린다. 근데 뮤텍스를 다 썼을 때 삭제하고 싶지 않으면 shapred_ptr의 삭제자를 사용해라

struct unlock
{
	template<typename T>
	void operator()(T* p) 
	{
		//unlock 하는 루틴~
	}
};

class Lock 
{
private:
	shared_ptr<Mutex>mutexPtr;		//원시 포인터대신에
				//shared_ptr을 사용
public:
	explicit Lock(Mutex* pm)		//shared_ptr을 초기화 하는데, 가리킬 포인터로
		: mutexPtr(pm, unlock())	//Mutex 객체의 포인터를 사용하고 삭제자로
	{								//unlock함수를 사용한다.

		lock(mutexPtr.get());		//get에 대한 이야기는 항목 15
	}
};

 

이 Lock 클래스가 이제는 소멸자를 선언하지 않는다. 이유는 필요 없어서 이다. 클래스의 소멸자는 비정적 데이터 멤버의 소멸자를 자동으로 호출하게 되어 있다. 이 '비정적 데이터 멤버'에 대해 해당하는 것이 mutex-ptr이다. 그리고 mutex-ptr의 소멸자는 뮤텍스의 참조 카운트가 0이 될 때 삭제자(unlock)를 자동으로 호출한다.

 

(소멸자 사용 시 주석에 "객체 소멸 과정을 잊은 게 아니라 컴파일러가 생성한 소멸자를 통해 동작한다" 라고 써놓자)

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading