[C++] EMCP Item 20: use std::weak_ptr for std::shared_ptr-like pointers that can dangle.
shared_ptr 처럼 작동하지만 대상을 잃을 수도 있는 경우 shared_ptr 사용
대상의 존재 유/무를 검출 가능해야 함
weak_ptr은 shared_ptr의 보강 용도임
auto spw = std::make_shared<Widget>();
std::weak_ptr<Widget> wpw(spw);
spw = nullptr;
if (wpw.expired()) … <-- expired 되었음을 확인 할 수 있음
weak_ptr을 사용하는 경우는,
caching
observer lists
shared_ptr cycle의 prevention
shared_ptr 끼리의 상호 참조는,
서로 reference count를 지니기에,
서로 소멸을 시킬 수 없게 만들기도 함 -> leak
이런 경우, weak_ptr을 사용해서
shared_ptr의 소멸 시, weak_ptr이 dangle 되게 함
weak_ptr은 dangle 상황을 감지할 수 있음
auto spw = std::make_shared<Widget>();
std::weak_ptr<Widget> wpw(spw);
if (wpw.expired()) {
...
weak_ptr에서 shared_ptr 획득 방법
1) lock 사용
std::shared_ptr<Widget> spw1 = wpw.lock();
auto spw2 = wpw.lock();
2) 생성자 인수로 지정
std::shared_ptr<Widget> spw3(wpw);
argument로 받을 시, wpw가 expired 된 상태면,
shared_ptr 내 std::bad_weak_ptr exception 이 발생함
왜? weak_ptr을 사용하나?
1) cacheable 객체
모든 ref. 소멸 시 함께 소멸 시킬 필요가 있는 경우
std::shared_ptr<const Widget> fastLoadWidget(WidgetID id) {
static std::unordered_map<WidgetID,
std::weak_ptr<const Widget>> cache;
auto objPtr = cache[id].lock(); // objPtr is std::shared_ptr
// to cached object (or null
// if object's not in cache)
if (!objPtr) { // if not in cache,
objPtr = loadWidget(id); // load it
cache[id] = objPtr; // cache it
}
return objPtr;
}
unordered_map 즉, hash table contaner 사용
그냥,
<ID, shared_ptr<...>>로 table을 구성하면 되지 않나?
이게 더 쉬운것 아닌가?
2) observer design pattern
관찰 대상은 자신이 파괴된 관찰자에 접근하는 일이 없도록 보장할 필요가 있음
3) circular dependency
+---+ shared_ptr +---+ shared_ptr +---+
| A |----------------> | B | <-------------- | C |
+---+ +---+ +---+
+---+ shared_ptr +---+ shared_ptr +---+
| A |----------------> | B | <-------------- | C |
+---+ +---+ +---+
^ |
| shared_ptr |
+----------------------+
위 경우 순환 고리(cycle)를 형성하기에
A와 B 둘 다 파괴되지 못함
+---+ shared_ptr +---+ shared_ptr +---+
| A |----------------> | B | <-------------- | C |
+---+ +---+ +---+
^ |
| weak_ptr |
+----------------------+
weak_ptr 사용 시
cycle이 있지만, 파괴될 수 있음
tree등 엄격히 계층적인 자료구조에서는 보통 부모만 자식을 소유
부모 노드 파괴 시 자식 노드도 파괴됨
따라서 부모에서 자식으로의 링크는 일반적으로 unique_ptr을 사용하는 것이 최선
엄격히 통제적이지 않는 자료 구조에서는 weak_ptr 사용 가능
효율성
weak_ptr은 shared_ptr과 본질적으로 동일
그 크기가 동일
단, weak_ptr은 객체의 소유권 공유에 참여하지 않음
Things to remember
1) shared_ptr과 동일하나 대상을 잃어도 되는 pointer로서 weak_ptr 사용
2) 사용 경우는 caching, observer pattern, cycle 제거 등이 있음
'programming > programming general' 카테고리의 다른 글
[C++] EMCP Lambda expression (0) | 2018.03.25 |
---|---|
[C++] EMCP Item 19: 자원에 대한 공유 소유권을 위해서는 shared_ptr을 사용하라 (0) | 2018.03.25 |
[C++] Smart Pointers (0) | 2018.03.25 |
[C++] Atomic class 구현 (0) | 2015.07.04 |
댓글