자원 관리 클래스에 대한 고찰
항목 13에서 처럼 힙 기반 자원이 아니라면 어떻게 관리해야 하는가?
자원 관리 클래스를 결국 만들어야 한다.
예를 들어 Mutex 타입의 객체를 조작하는 C API 를 사용중이라고 가정해보자.
해당 API 는 lock, unlock 함수를 제공한다.
void lock(Mutex *pm);
void unlock(Mutext *pm);
이전에 걸어 놓은 뮤텍스 잠금을 잊지 않고 풀어주기 위한 용도의 잠금 관리 클래스를 만들고 싶다면
이 클래스는 RAII 법칙을 따라 구성한다. == 생성 시에 자원을 획득, 소멸 시에 자원을 해제!
잠금 관리 클래스
class Lock {
public:
explicit Lock(Mutext *pm) : mutexPtr(pm){
lock(mutexPtr);
}
~Lock() { unlock(mutexPtr);}
private:
Mutext *mutexPtr;
}
사용 예
Mutext m;
{
Lock m1(&m); //뮤텍스에 잠금을 건다.
} //블록의 끝이다. Lock 이 소멸자를 호출하면서 잠금도 풀린다.
문제점
그러나 Lock 객체가 복사 된다면?
Lock ml1(&m);
Lock m12(&ml1); // ml1 을 ml2 에 복사한다. 어떻게 되어야 맞는 걸까?
RAII 객체의 복사 동작
RAII 객체가 복사가 될 때 어떤 동작이 이루어 져야 하는가에 대한 선택지는 다음이 있다.
1. 복사를 금지한다.
RAII 객체가 복사되도록 놔두는 것 자체가 말이 안되는 경우가 있다.
앞의 Lock 클래스만 해도 스레드 동기화에 대한 객체의 '사본'은 의미가 없다.
복사를 막는 방법은 항목 6을 참고하자. (복사 함수를 private 으로 만들자)
2. 관리하고 있는 자원에 대한 참조 카운팅을 수행한다.
shared_ptr 이 떠오는 방법이다.
Lock 이 참조 카운팅 방식으로 돌아가길 원하면 , mutexPtr 타입을 shared_ptr<Mutex>
로 바꾸면 되지 않는가?
shared_ptr은 참조 카운트가 0 이 될 때 자원을 해제해서 이렇게 하면 Mutex 가 삭제될 수 있다.
그럼 shared_ptr에 삭제자(deleter) 를 지정하자!
삭제자는 shared_ptr 에서 참조 카운팅이 0이 되었을 때 호출되는 함수다.
shated_ptr 의 생성자의 두번째 매개변수에 넣어줄 수 있다.
아래는 shared_ptr 을 이용해 바꾼 코드다. 소멸자는 이제 필요없다!
class Lock {
public:
explicit Lock(Mutext *pm) : mutexPtr(pm,unlock){ //deleter 로 unlock 함수 지정!
lock(mutexPtr.get()); //get 에 관한것은 항목 15를 보자
}
//객체 소멸과정을 잊은게 아니라 컴파일러가 생성한 소멸자를 통해 동작한다.
//클래스의 소멸자는 비정적 데이터 멤버의 소멸자를 자동 호출하게 되어 있다.
private:
shared_ptr<Mutex> mutexPtr;
}
3. 관리하고 있는 자원을 진짜로 복사한다.
deep copy 를 수행하자.
표준 string 타입을 구현해 놓은 것 중에, 문자열을 구성하는 원소들을 힙 메모리에 저장해 놓고
이 메모리에 대한 포인터를 데이터 멤버로 갖고 있는 경우가 있다.
이때 이 객체를 복사하면, 사본은 포인터 및 그 포인터가 가리기는 새로운 힙 메모리를 갖게 된다.
4. 관리하고 있는 자원의 소유권을 옮긴다.
auto_ptr 의 복사 동작이 이렇게 구현되어 있다.
복사가 아니라 이동이다.
요약
- RAII 객체의 복사는 해당 객체자 관리하는 자원의 복사 문제를 안고 가기 때문에, 그 자원을 어떻게 복사하느냐에 따라
RAII 복사 동작이 결정 된다. - RAII 클래스에 구현하는 일반적인 복사 동작은 복사를 금지 or 참조 카운팅을 해 주는 선으로 마무리 하는 것이다.
'C++ > Effective C++' 카테고리의 다른 글
항목 17: new 로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 (0) | 2020.09.25 |
---|---|
항목 16: new 및 delete 를 사용할 때는 형태를 반드시 맞추자 (0) | 2020.09.24 |
항목 15: 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2020.09.24 |
항목 13: 자원 관리에는 객체가 그만! (0) | 2020.09.23 |
항목 31 : 파일사이의 컴파일 의존성을 줄이자 (0) | 2020.09.22 |