티스토리 뷰
C++/Effective Modern C++
[Effective Modern C++] 항목 18. 소유권 독점 자원의 관리에는 std::unique_ptr를 사용하라
pppgod 2019. 11. 3. 15:38std::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++
'C++ > Effective Modern C++' 카테고리의 다른 글
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- Join
- Forwarding
- forward
- 다이소
- Effective Modern C++
- 보편참조
- async
- C++11
- auto
- detach
- MOVE
- Future
- 포인터
- const
- Override
- Overloading
- std::forward
- Modern
- C++
- C
- Perfect
- 보편 참조
- CPP
- C++14
- std::move
- 발아시기
- 람다
- Effective
- thread
- Unreal
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함