자원은 모두 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 클래스에 구현하는 일반적인 복사 동작은 복사를 금지하거나 참조 카운팅을 해 주는 선으로 마무리 하는 것입니다. 하지만 이 외의 방법들도 가능하니 참고해 둡시다. 


+ Recent posts