티스토리 뷰

 std::unique_ptr 는 독점적 소유권 의미론을 재현하는 클래스이다. 그에 따라 복사를 허용하지 않으며, 오직 이동만 가능하다. std::unique_ptr raw 포인터와 거의 같은 크기를 갖는다. 메모리와 CPU 성능이 넉넉하지 않더라도 사용하기에 충분하다는 뜻이다.

 std::unique_ptr 객체는 자신이 파괴될 때, 가르키는 자원 또한 함께 파괴된다. std::unique_ptr 가 파괴될 때 수행되는 커스텀 삭제자를 사용할 수 있다. 팩터리 패턴의 함수의 예시를 살펴보자.

auto delInvmt = [](Investment* pInvestment)
                {
                    makeLogEntry(pInvestment);
                    delete pInvestment;
                };
                
template<typename... Ts>
std::unique_ptr<Investment, decltype(delInvmt)>
makeInvsetment(Ts&&... params)
{
    std::unique_ptr<Investment, decltype(delInvmt)>
      pInv(nullptr, delInvmt);
      
    if ( /* Stock 객체를 생성해야 하는 경우 */ )
    {
        pInv.reset(new stock(std::forward<Ts>(params)...));
    }
    else if ( /* Bond 객체를 생성해야 하는 경우 */ )
    {
        pInv.reset(Bond stock(std::forward<Ts>(params)...));
    }
    else if ( /* RealEstate 객체를 생성해야 하는 경우 */ )
    {
        pInv.reset(new RealEstate(std::forward<Ts>(params)...));
    }
    
    return pInv;
}

 위의 함수를 사용하는 호출자는 반환받은 객체의 소멸이 오직 한 번만 일어난다는 것과 소멸 방식에 대해 신경을 쓰지 않아도 된다는 장점이 생긴다.

 C++14 에서 위의 코드를 작성한다면 보다 간결하고 캡슐화된 방식으로 구현이 가능하다.

template<typename... Ts>
auto makeInvsetment(Ts&&... params)
{
    auto delInvmt = [](Invsetment* pInvestment)
    {
        makeLogEntry(pInvestment);
        delete pInvestment;
    };
    
    std::unique_ptr<Investment, decltype(delInvmt)>
      pInv(nullptr, delInvmt);
      
    if ( /* Stock 객체를 생성해야 하는 경우 */ )
    {
        pInv.reset(new stock(std::forward<Ts>(params)...));
    }
    else if ( /* Bond 객체를 생성해야 하는 경우 */ )
    {
        pInv.reset(Bond stock(std::forward<Ts>(params)...));
    }
    else if ( /* RealEstate 객체를 생성해야 하는 경우 */ )
    {
        pInv.reset(new RealEstate(std::forward<Ts>(params)...));
    }
    
    return pInv;
}

 std::unique_ptr 의 크기

 std::unique_ptr 의 크기는 raw 포인터와 거의 같다고 하였다. 그런데 커스텀 삭제자를 사용하는 경우에는 std::unique_ptr 의 크기가 1 워드에서 2 워드로 증가한다. 삭제자가 함수 객체일 때에는 그 함수 객체에 저장된 상태의 크기만큼 증가하고, 갈무리 없는 람다식의 경우에는 크기의 변화가 없다. 따라서 두 가지 모두 구현 가능하다면 람다식을 사용하는 것이 바람직하다.

// 람다식으로 작성한 경우
auto delInvmt = [](Investment* pInvestment)
                {
                    makeLogEntry(pInvestment);
                    delete pInvestment;
                };
                
template<typename... Ts>
std::unique_ptr<Investment, decltype(delInvmt)>  // 반환 형식은 Investment* 와 같은 크기
makeInvsetment(Ts&&... params);


// 함수 형태로 작성한 경우
void delInvmt2(Investment* pInvestment)
{
    makeLogEntry(pInvestment);
    delete pInvestment;
};

template<typename... Ts>
std::unique_ptr<Investment, 
                void (*)(Investment(*)>  // 반환 형식은 Investment* 에 함수 포인터의 크기를 더한 크기
makeInvsetment(Ts&&... params);

 

참고 서적

스콧 마이어스, Effective Modern C++
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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 28
29 30 31
글 보관함