unique_ptr은 이름에서 알수있듯이 독점적 소유권을 가지고 있다. unique_ptr은 복사가 허용되지 않고 이동만 가능하다.

소멸 시 자신이 가리키는 자원(원시 포인터)을 파괴한다. 기본적으로 소유하고 있는 원시 포인터에 delete를 적용해서 파괴하게 된다.

 

template<typename... Ts>
std::unique_ptr<Investment> makeInvestment(Ts&&... params); // C++11

unique_ptr은 흔히 팩토리 함수의 반환 타입으로 자주 쓰인다.

 

unique_ptr이 소멸하며 소유중인 원시 포인터를 파괴할 때 기본적으로 delete를 사용하지만 필요하다면 unique_ptr 객체를 생성할 때 커스텀 삭제자를 사용하도록 지정하는 것도 가능하다.

 

auto delInvmt = [](Investment* pInvestment) {
    makeLogEntry(pInvestment); // 로그 기록
    delete pInvestment;
};

template<typename... Ts>
std::unique_ptr<Investment, decltype(delInvmt)> makeInvestment(Ts&&... params) {
    std::unique_ptr<Investment, decltype(delInvmt)> pInv(nullptr, delInvmt);
    ...
}

삭제하기 전에 로그를 남긴 뒤에 삭제하는 커스텀 삭제자를 만들수도 있다. 다만 타입이 파생클래스인 경우 기반클래스의 포인터를 통해 소멸자를 호출하기 때문에 반드시 가상 소멸자이어야 한다.

 

기본 삭제자를 사용하는 경우 unique_ptr의 객체 크기는 원시 포인터의 크기와 같을거라고 가정하는 것이 합당하지만 커스텀 삭제자를 사용하는 경우 크기가 증가하게 된다.

일반적으로는 함수 포인터를 삭제자로 지정한 경우 1워드만 증가하지만 상태를 많이 가지는 함수 객체라면 그 크기만큼 증가하게 된다. 그래서 가능하면 람다식으로 구현하는 것을 선호하는 것이 좋다.

 

unique_ptr에는 원시 포인터를 직접 대입하게 되면 컴파일 에러가 발생한다. 만약 이게 허용된다면 암묵적 변환이 성립하기 때문에 그렇다.

 

unique_ptr은 팩토리 함수 뿐만 아니라 pimpl 관용구의 구현에 더 잘 쓰인다. 이 내용은 추후 다루도록 한다.

 

std::shared_ptr<Investment> sp = makeInvestment(...);

또한 unique_ptr은 shared_ptr로의 변환도 매우 손쉽고 효율적이다.

팩토리 함수는 반환된 객체가 독점적인 소유인지, 소유권이 공유되는지를 미리 알 수 없다. 하지만 unique_ptr로 반환한다면 둘 중 어느것도 될 수 있는 유연성이 생긴다.

 

◾ std::unique_ptr는 독점 소유권 의미론을 가진 자원의 관리를 위한, 작고 빠른 이동 전용 스마트 포인터이다.

◾ 기본적으로 자원 파괴는 delete를 통해 일어나나, 커스텀 삭제자를 지정할 수도 있다. 상태 있는 삭제자나 함수 포인터를 사용하면 std::unique_ptr 객체의 크기가 커진다.

◾ std::unique_ptr을 std::shared_ptr로 손쉽게 변환할 수 있다.

+ Recent posts