본문 바로가기

Library/C/C++

단위 전략에 기반한 스마트 포인터의 생성자

스마트 포인터를 구현할 때, 단위 전략 기반의 스마트 포인터가 아니라면 다른 타입으로 생성된 스마트 포인터를 인자로 받는 생성자를 구현하는 것은 필수다. 예를 들어, Dervied 클래스가 Base 클래스를 상속 받았다면, 다음의 코드는 컴파일에 문제가 없어야 한다.


smatr_ptr< Base > sp_b (new smart_ptr< Derived >);
// 또는,
smart_ptr< Base >sp_b(new Derived);


이것은, 원시 포인터를 사용한 코드가 다음과 같기 때문이다.


Base * pBase = new Derived;


문제는 스마트 포인터가 여러 템플릿 인자를 가지는, 단위 전략 기반의 스마트 포인터가 이런 형식의 생성을 지원해야 하는지 여부이다. 즉, 생성된 타입에 대한 정보만 템플릿 인자로 가지는 스마트 포인터라면 다른 타입의 인자를 가지는 스마트 포인터를 기반으로 생성되는 생성자를 제공하는게 맞겠지만, 여러 단위 전략을 가지는 스마트 포인터는 그렇지 않을 수도 있다. 예를 들어, 소유권 관리를 단위 전략으로 구성한 스마트 포인터를 예로 들어보자. 레퍼런스 카운팅되는 관리 전략과, 쿠다(CUDA)에 의한 메모리 관리를 책임지는 소유권 관리 전략을 선택한 스마트 포인터가 인스턴스화 되었다고 생각해보자.


smart_ptr< Base, RefCount > sp_base;
smart_ptr< Base, Cuda > sp_cuda;


스마트 포인터에서, 다른 스마트 포인터가 가지는 포인터로부터 새로운 스마트 포인터를 생성하기를 원하므로, 다음과 같은 코드를 쓸 수 있을 것이다.


smart_ptr< Derived, RefCount > sp_derived;
smart_ptr< Base, RefCount > sp_base(sp_derived);


그러나, 생성하려는 인스턴스가 연관성이 있다고 하더라도 , 다른 소유권 관리 전략을 가지는 스마트 포인터에서 새로운 스마트 포인터를 생성하는 것은 쉽게 정의될 수 없다.


smart_ptr< Derived, Cuda > sp_cuda;
smart_ptr< Base, RefCount > sp_base(sp_cuda);
/* sp_cuda와 sp_base의 관리 대상은 동일하지 않기 때문에,
논리적으로 맞지 않을 수 있다 */


왜냐하면, 단위 전략 기반의 스마트 포인터에서 실제로 포인터를 소유하는 것은 관리 전략이므로 서로 다른 관리 전략을 가지는 스마트 포인터를 대상으로 새로운 스마트 포인터를 생성하는 것은 스마트 포인터에 의해 관리되는 자원의 충돌을 야기할 가능성이 높기 때문이다. 즉, 관리 전략들의 공통 인터페이스를 정의하지 않는 한, 다른 스마트 포인터가 관리하는 개체를 가져와서 새롭게 스마트 포인터를 생성하는 것은 자원 관리의 일관성을 해칠 수도 있다. 더구나, 각각의 관리 전략들은 각 상황에 특화된 자원 관리 방법과 데이터 멤버들을 가지기 때문에, 서로 다른 관리 전략이 어떤 정보를 기반으로 자신의 스마트 포인터를 구축해야 할지 결정하기 곤란하다.


template< typename T >
smart_ptr(const smart_ptr< T > &p)
{
    ....
}


자신이 직접 포인터를 가지는 단순한 스마트 포인터라면 이와 같은 생성자를 제공하는 것이 필수지만, 개체 소유권을 단위 전략으로 가지는 스마트 포인터는 그렇지 않다. 특히, 멤버 함수는 디폴트 템플릿 인자를 가질 수 없기 때문에, 사용 측면에서 불편할 수도 있다. 결론적으로, 단위 전략 기반의 스마트 포인터는 다른 스마트 포인터로부터 새로운 스마트 포인터를 생성하는 생성자를 반드시 가져야 할 필요는 없다.