티스토리 뷰
[Effective Modern C++] 항목 20. std::shared_ptr처럼 작동하되 대상을 잃을 수도 있는 포인터가 필요하면 std::weak_ptr를 사용하라
pppgod 2019. 11. 11. 00:10앞서 살펴본 스마트 포인터들 중에서 가장 이해하기 어려운 것이 weak_ptr 이다. unique_ptr 와 shared_ptr 는 목적이 분명하지만 weak_ptr 는 경험하지 않는다면 언제 써야하는지 알기 어렵다. 이 포스트에서 weak_ptr 를 사용해야하는 경우를 살펴보자.
사용법
weak_ptr 는 언제든 소멸될 수 있는 객체를 사용할 때 쓰는 스마트 포인터이다. weak_ptr 는 shared_ptr 와 함께 사용하는 스마트 포인터이지만 reference_count 를 증가시키지 않는다. 다시 말하면 객체의 소멸에 관여하지 않는다는 뜻이다. 그로 인한 문제로 사용하려고 하는 순간 이미 객체가 소멸될 수도 있는 것이다. 만약 객체를 사용할 때, 객체가 소멸되는 경우 crash 가 발생하게 되는 것이다. 이러한 문제 상황이 발생하는 것을 막기 위하여 weak_ptr 는 shared_ptr 로 변환해서 사용해야만 한다.
std::shared_ptr<Widget> spw1 = wpw.lock();
auto spw2 = wpw.lock();
사용하는 상황
캐시를 사용하는 경우
데이터 베이스에서 가져온 데이터를 캐시를 해놓는다고 가정하자. 캐시를 해놓은 객체를 소멸시키지 않는다면 성능상의 문제가 발생할 것이므로 사용하지 않는 객체는 소멸을 시켜야한다. 만약 캐시에서 reference count 를 증가시킨다면 소멸시켜야하는 시점에 대해서 알기 어려울 것이다. reference count 를 증가시키지 않으면서 언제든 소멸시킬 수 있는 상황 속에서 weak_ptr 는 아주 적절하다. 다음과 같이 사용할 수 있다.
std::shared_ptr<const Widget> fastLoadWidget(WidgetID id)
{
static std::unordered_map<WidgetID,
std::weak_ptr<const Widget>> cache;
auto objPtr = cache[id].lock();
if (!objPtr) {
objPtr = loadWidget(id);
cache[id] = objPtr;
}
return objPtr;
}
옵저버 패턴
옵저버 패턴에서 관찰자는 관찰 대상들을 담는 컨테이너를 사용한다. 관찰자들은 관찰 대상들의 소멸 여부에는 관심이 있지만 수명에는 관여하지 않는다. 따라서 옵저버 패턴을 사용하는 상황이라면 weak_ptr 를 사용하는 것이 적절하다.
순환참조
스마트 포인터를 사용하는 경우에 발생하는 가장 큰 문제이며 weak_ptr 를 사용하는 가장 큰 이유이기도 하다. A와 B, C 객체가 존재한다고 하자. A 와 C 가 B 객체를 소유하는 상황을 가정해보자. 이 상황 속에서 B 가 A 를 가르키는 포인터가 필요하게 된 경우 어떤 포인터를 사용해야 하는지 알아보자.
-
생 포인터
위의 상황에서 A 가 소멸된다면 B 는 소멸되었는지 알 수가 없어 널 포인터에 접근하게 된다.
-
std::shared_ptr
A 가 B 를 소유하고 B 가 A 를 소유하게 된다. 순환참조를 하게 되는 상황으로 서로 영원히 소멸되지 않는다.
-
std::weak_ptr
가장 이상적인 선택으로 널 포인터에 접근하지도 순환참조가 발생하지도 않는다.
참고 서적
스콧 마이어스, Effective Modern C++
'C++ > Effective Modern C++' 카테고리의 다른 글
- Total
- Today
- Yesterday
- Future
- 람다
- const
- Override
- auto
- C++
- C++11
- std::move
- 다이소
- 보편 참조
- 보편참조
- Effective
- C++14
- Unreal
- Join
- Perfect
- thread
- 포인터
- MOVE
- C
- async
- forward
- 발아시기
- std::forward
- detach
- CPP
- Effective Modern C++
- Overloading
- Forwarding
- Modern
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |