카테고리 없음

[C++] EMCP Item 18: 독점적 소유권 (Exclusive-ownership) 자원 관리 시, unique_ptr을 사용 하라

Roien 2018. 3. 25.
반응형
기본적으로 unique_ptr은 raw pointer와 동일 size (라고 가정하는 것이 합리적)
. 성능과 memory 자원에 영향을 받지 않음

unique_ptr
copy 불가 (move-only 임)
   - 동일 소유 상황을 막기 위함
   - 이동만 허용
소유하는 자원의 destruction은 delete로 수행됨


ex.
factory with unique_ptr


class Investment { … };
class Stock: public Investment { … };
class Bond:  public Investment { … };
class RealEstate: public Investment { … };


// a factory function
template<typename... Ts> // return std::unique_ptr
std::unique_ptr<Investment> // to an object created
makeInvestment(Ts&&... params); // from the given args


auto pInvestment = makeInvestment( arguments );


unique_ptr이 container로 이동 되면, container elemetn는
객체의 data member로 이동됨
object가 나중에 제거되면 object의 unique_ptr data member도 제거됨

이 ownership chain이 exception이나 다른 atypical control flow(early function return, loop의 break 등)에 의해서 interrupt되면,  unique_ptr의 소멸자가 불리게 되며, resource도 제거됨



ex. dustom deleter 사용하는 unique_ptr 사용 factory function
  자원 생성/소멸에 대해서 신경 쓸 필요가 없어짐

auto delInvmt = [](Investment* pInvestment) // custom
                        // deleter
makeLogEntry(pInvestment);              // (a lambda
delete pInvestment;                  // expression)
};

template<typename... Ts> // revised
std::unique_ptr<Investment, decltype(delInvmt)> // return type
makeInvestment(Ts&&... params)
{
std::unique_ptr<Investment, decltype(delInvmt)> // ptr to be returned
 pInv(nullptr, delInvmt);
if ( /* a Stock object should be created */ )
{
pInv.reset(new Stock(std::forward<Ts>(params)...)); // perfect forwarding
}
else if ( /* a Bond object should be created */ )
{
pInv.reset(new Bond(std::forward<Ts>(params)...));
}
else if ( /* a RealEstate object should be created */ )
{
pInv.reset(new RealEstate(std::forward<Ts>(params)...));
}
return pInv;
}


  unique_ptr을 사용
   : 소멸이 정확히 한 번만 일어남을 보장됨을 의미


smart pointer로의 assign은 불가하여 reset을 사용
custom deleter는 Investment *를 받음
이를 위해 Investment는 반드시 virtual destructor를 지녀야 함

class Investment {
public:
…  // essential
virtual ~Investment();  // design
…  // component!
};



C++14에서는 함수 반환 형식의 deduction(연혁) 지원
makeInvestment 함수 내에서 소멸자를 허용

template<typename... Ts>
auto makeInvestment(Ts&&... params) // C++14
{
auto delInvmt = [](Investment* pInvestment) // this is now
// inside
makeLogEntry(pInvestment);  // makedelete
pInvestment;  // Investment
};

std::unique_ptr<Investment, decltype(delInvmt)>
pInv(nullptr, delInvmt);

...
}


  기본 삭제자(즉 delete)를 사용할 때에는 unique_ptr 객체의 크기가 raw pointer 크기와 같으리라고 가정하는 것이 합당
  그러나 custom deleter를 사용하면 상황이 달라짐 - 이 경우, unique_ptr의 크기는 1 or 2 words 증가

ex. custom deleter

auto delInvmt1 = [](Investment* pInvestment)    // <-- custom deleter
  {
      makeLogEntry(pInvestment);                // as stateless lambda
      delete pInvestment;
  };

template<typename... Ts>                          // return type has size of
std::unique_ptr<Investment, decltype(delInvmt1)>  // Investment*
makeInvestment(Ts&&... args);

void delInvmt2(Investment* pInvestment)           // custom deleter
{
    makeLogEntry(pInvestment); // as function
    delete pInvestment;
}

template<typename... Ts>      // return type has size of Investment*
std::unique_ptr<Investment,   // plus at least size of function pointer!
    void (*)(Investment*)> 
makeInvestment(Ts&&... params);


  unique_ptr의 흔한 용도가 factory function 만은 아님
  pimpl로 더 인기 있음

  unique_ptr에서 shared_ptr로의 변환이 가능함
  std::shared_ptr<Investment> sp = makeInvestment(param..);


stateless function objects
: Lambda expression with no captures

stateless function object로는 function pointer 보다,
Lambda with no captures가 더 선호됨


unique_ptr은
1) unique_ptr<T>
2_ unique_ptr<T[]>
array는 사용하지 않는 것이 좋음
std::array, vector, string 등이 있기 때문

unique_ptr<T[]>를 사용할 만한 경우는,
C-like API를 사용하는 경우에만 한정됨

3) shared_ptr로의 conversion
std::shared_ptr<Investment> sp =
makeInvestment( arguments );


Things to remember
  1) unique_ptr은 독점 소유권 semantics를 지닌 자원 관리를 위한 작고 빠른 이동 전용 smart pointer임
  2) 기본적으로 파괴는 delete를 통해 일어나나, custom deleter 지정 가능
     함수 pointer를 사용하면 unique_ptr 객체의 크기가 커짐
  3) unique_ptr을 shared_ptr로 쉽게 변환 가능


반응형

댓글