■ shared_ptr의 한계점
shared_ptr<Knight> k1(new Knight());
shared_ptr<Knight> k2(new Knight());
k1->_target = k2;
k2->_target = k1;
위와 같이 서로를 참조하고 있을 때 둘의 Ref Count는 각각 2가 된다.
애당초 ref count가 0이 되어야 메모리를 해제(delete)시키는데 k1이 소멸되어 ref count를 -1한다고 해도 ref count는 여전히 1이 되어버린다.
그러면 결국엔 서로를 추적하고 있는 상황에선 메모리 해제가 일어나지 않는 버그가 발생하므로 메모리 릭(Memory Leak)이 일어난다.
▼ Ref Count가 0이 안되어서 소멸자가 호출이 안되는 상황
이런 상황에선 임의로 우리가 어떤 유저가 로그아웃을 해가지고 빠져나갔다면 k1->_target.reset(); 같은 코드를 넣어줌으로써 강제로 끊어줄 수 밖에 없다.
shared_ptr만 사용할 경우 위와 같은 문제가 발생할 수 있는데 weak_ptr까지 사용한다면 예방할 수가 있다.
■ weak_ptr
생명 주기에는 영향을 주지 않고 [ref count는 건드리지 않고] 경우에 따라 아직 날라가지 않았으면 다시 shared_ptr로 변환해서 사용할 수 있다.
독립적으로 사용할 수 없고 shared_ptr의 사이클 문제를 보충하기 위해 생겨난 shared-ptr 의존적인 포인터이다.
아래와 같이 expired 되었는지 확인하고 접근이 가능하다면 lock()함수를 통해 shared_ptr로 캐스팅 후 사용할 수 있다.
[스마트 포인터 활용 두 가지 방법]
1. shared_ptr만 사용할거면 생명 사이클을 알아서 잘 관리해줘야 하고
2. shared_ptr, weak_ptr를 사용한다면 expired(), lock()같은 함수를 통해 실제로 메모리가 유효한지 체크 후 사용해줘야 한다.
[요약]
Shared_ptr은 레퍼런스 카운트라는 변수를 둬서 참조 개수를 관리하는 포인터이다. Shared_ptr로 다른 애를 복사할 때마다 즉, 참조 횟수가 늘어날 때마다 레퍼런스 카운터를 늘려준다. 그리고 이러한 레퍼런스 카운트는 본인을 참조하는 개체가 참조를 해제 할 때마다 -1씩 줄어드는데 0이 될때만 개체의 메모리를 실제로 해제하는 방식이다.
Weak_ptr가 나온 이유는 서로 참조하는 사이클이 발생하면 shared_ptr이 서로를 절대 놔주지 않는 문제가 발생하기 때문에 [Deadlock 같은 상황] 그걸 보완하기 위한 용도로 weak pointer가 등장했다.
weak pointer는 레퍼런스 카운트 자체에는 영향을 주지 않지만 Weak Count라는 것을 별도로 관리하고 있고 그 레퍼런스 블록 자체를 weak pointer가 들고 있기 때문에 이를 이용하여 어떤 메모리가 날라갔는지 여부를 확인할 수 있다.
그 여부를 확인한 다음에 안전하게 접근을 하거나 날라갔으면 그냥 버리는 식으로 둘 중 하나를 선택할 수 있도록 도와주는 것이 weak pointer다.
▼ weak_ptr를 사용함으로써 소멸자가 호출되도록 설계한 결과
■ unique_ptr
복사 관련 함수(ex. 복사 생성, 복사 대입.. etc) 가 다 막혀있는 포인터.
하지만 유일하게 내용을 덮어씌우는 방식은 std::move를 통해 이동연산자를 호출하는 것이다.
'개발 (언어) > C++' 카테고리의 다른 글
[MultiThread] 캐시 및 CPU 명령어 파이프라인 (1) | 2024.04.07 |
---|---|
[MultiThread] 쓰레드 생성 (1) | 2024.04.07 |
[Modern C++] shared_ptr (0) | 2024.03.31 |
[Modern C++] rvalue-ref (오른값 참조) (0) | 2024.03.31 |
[Modern C++] Unicode, MBCS, WBCS (1) | 2024.03.29 |