Post

[ STUDY/Effective C++ ] 2022. 10. 28. 23:20

항목13에서 본 shared_ptr(auto_ptr은 이후에 삭제되었다고한다)은 힙이 아닌 다른 자원에는 맞지않다라는 견해가 일반적이다.

하지만 모든 자원이 힙에서 생기지는 않는다. 그래서 자원 관리 클래스를 우리가 스스로 만들어야할 필요성이 있다.

 

class Lock{
public:
    explicit Lock(Mutex *pm)
    :mutexPtr(pm)
    { lock(mutexPtr);}
    
    ~Lock() {unlock(mutexPtr);}
    
    private:
    Mutex *mutexPtr;
};

잠금을 관리하는 클래스를 하나 만들고 , RAII법칙을 따라한다고하자. 

Lock m11(&m);
Lock m12(m11);

하지만 여기서 복사를 하게 된다면 어떻게 될까?

 

복사할때 이루어지는 동작과 관련해서 선택지를 고를 수 있다.

 

1. 복사를 금지한다.

복사하면 안되는 RAII클래스(위와 같은 Lock)의 경우에는 복사가 아예 안되도록 막아놓아야한다.

이 경우에는 복사함수를 private 멤버로 만들면된다.

 

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

해당 자원을 참조화는 객체의 개수에 대한 카운트를 증가시키는 식으로 RAII 객체의 복사 동작을 만들어야한다.

shared_ptr이 이러한 방식을 사용하고있다.

 

하지만, shared_ptr의 경우에는 참조카운트가 0이되면 삭제가 되기때문에 Lock을 해제만 하고싶지 삭제를 하고싶지않은 사람에게는 다소 목적이 안맞을 수 있다.

class Lock {
public:
    explict Lock(Mutex *pm)
    :mutexPtr(pm, unlock) //삭제자로 umlock함수 사용
    {
    lock(mutexPtr.get());
    }
private:
    std::tr1::shared_ptr<Mutex> mutexPtr; //원시포인터 대신, shared_ptr사용
};

이런경우에는 shared_ptr에 '삭제자'(deleter)라는 것이 있다. 삭제자란 shared_ptr의 참조 카운트가 0이되면 호출되는 함수 혹은 함수객체를 일컫는 말이다. 이 삭제자를 shared_ptr 생성자의 두번째 매개변수에다가 선택하여 넣어줄 수가 있다.

 

이러면 소멸자를 선언할 필요 없이 비정적데이터 멤버(mutexPtr)의 소멸자가 자동으로 호출되는데, mutexPtr의 소멸자는 shared_ptr의 삭제자가 자동으로 호출되어진다!

 

3. 관리하고 있는 자원을 진짜로 복사한다.

 자원관리 객체를 복사하면 그 객체의 자원까지 복사되어야하기때문에 깊은 복사를 수행해야한다. 

 

4. 관리하고 있는 자원의 소유권을 옮긴다.

 

▲ top