자원은 모두 Heap에서 생성되는 것은 아니기 때문에 동적 할당 객체가 아닌경우에는 스마트 포인터가 적절하지 않습니다.
이와 같은경우 사용자가 직접 자원관리 클래스를 만들어줘야 합니다.
다음과 같이 RAII 법칙을 따라 클래스를 구성합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Lock { private: Mutex* mutexPtr; public: explicit Lock(Mutex *pm) : mutexPtr(pm) { lock(mutexPtr); } ~Lock() { unlock(mutexPtr); } }; void main() { Mutex m; { //임계 영역을 정하기 위해 블록을 만듭니다. Lock m1(&m); } // 블록의 끝입니다. 뮤텍스에 걸렸던 잠금이 // 자동으로 풀립니다. } |
이러한 RAII클래스를 구현했지만, 문제는 RAII 객체가 복사될때는 어떤 동작을 이루어져야 하는지가 참 힘들게 합니다. 실제로 RAII 클래스는 복사되도록 놔두는 것 자체가 말이 안되는 경우가 꽤 많습니다.
자 그럼 복사에 대한 문제해결을 하기위한 방법을 알아봅시다.
첫째, 복사를 금지합니다.
복사하면 안되는 RAII클래스에 대해서는 반드시 복사가 되지 않도록 막아야 합니다. 사본이 필요없는경우 입니다. 위의 예제도 이 부류에 속합니다.( Uncopyable 클래스를 사용 )
둘째, 관리하고 있는 자원에 대해 참조 카운팅을 수행합니다.
std::shared_ptr을 이용하여 참조하는 객체의 갯수가 0이 될때 그지정한 객체를 삭제시킵니다.
하지만, 위의 클래스의 예를 들자면 우리는 Mutex는 삭제가 아니고 ulock만을 원합니다.
이럴땐 std::shared_ptr의 생성자중에 삭제자를 지정할 수있는 생성자를 사용합니다.
삭제자란? tr1::shared_ptr이 유지하는 참조 카운트가 0이 되었을 때 호출되는 함수 혹은 함수 객체를 일컷습니다.
1 2 3 4 5 6 7 8 9 10 11 12 | class Lock { private: std::tr1::shared_ptr<Mutex> mutexPtr; public: // unlock 함수포인터를 생성자 인자로 넘겨줌 (삭제자 지정) explicit Lock(Mutex *pm) : mutexPtr(pm, unlock) { lock(mutexPtr); } //소멸자가 사라짐 }; |
셋째, 관리하고 있는 자원을 진짜로 복사합니다.( deep copy )
자원의 깊은 복사를 수행하는 것입니다.( ex. std::string 타입의 복사 방식 )
넷째, 관리하고 있는 자원의 소유권을 옮깁니다.
std::auto_ptr 처럼 소유권은 단 한개만 가지고 싶을경우
이것 만은 잊지 말자!
◆ RAII 객체의 복사는 그 객체가 관리하는 자원의 복사 문제를 안고 가기 때문에, 그자원을 어떻게 복사하느냐에 따라 RAII 객체의 복사 동작이 결정됩니다.
◆ RAII 클래스에 구현하는 일반적인 복사 동작은 복사를 금지하거나 참조 카운팅을 해 주는 선으로 마무리 하는 것입니다. 하지만 이 외의 방법들도 가능하니 참고해 둡시다.
'0x0001 > Effective C++' 카테고리의 다른 글
[Effective C++] 항목 16 : new 및 delete를 사용할 때는 형태를 반드시 맞추자 (0) | 2019.02.13 |
---|---|
[Effective C++] 항목 15 : 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2019.02.12 |
[Effective C++] 항목 13 : 자원 관리에는 객체가 그만! (0) | 2019.02.12 |
[Effective C++] 항목 12 : 객체의 모든 부분을 빠짐없이 복사하자 (0) | 2019.02.12 |
[Effective C++] 항목 11 : operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자 (0) | 2019.02.12 |