본문 바로가기

C++

[C++] shared_ptr

shared_ptr은 unique_ptr과 달리 여러개의 스마트 포인터가 하나의 객체를 같이 소유하는 경우에 사용한다. 이 경우에는 특정 자원을 몇개의 객체에서 가리키는지 추적한 다음 그 수가 0이 되면 해제를 해주는 방식이다. WinApi 게임 프레임워크에서 사용했던 레퍼런스 카운트와 같은 방식이다.

 

 

여러개의 shared_ptr들은 같은 객체를 가리킬 수 있고, 같은 객체를 가리키는 shared_ptr의 수만큼 레퍼런스 카운트가 증가한다. 참조 개수가 몇 개 인지는 use_count 함수를 통해 알 수 있다. 

 

shared_ptr들이 레퍼런스 카운트를 저장하는 방식은, 제어 블록을 이용한다. 제어 블록을 동적으로 할당하고 shared_ptr들이 필요한 정보를 공유한다. shared_ptr를 복사 생성할 때마다 제어 블록의 위치를 공유하고 레퍼런스 카운트를 증가시킨다.

 

std::shared_ptr<A> p1(new A()); //동적할당 두번
std::shared_ptr<A> p1 = std::make_shared<A>(); //동적할당 한번

 

shared_ptr을 생성할 때는 make_shared를 사용하는 것이 좋다. 첫 줄의 코드는 A를 생성하기 위해 동적 할당을 한번 하고 shared_ptr의 제어 블록을 동적으로 할당해야 하기 때문에 두번의 동적 할당이 발생한다. make_shared 함수는 객체 A와  제어블록까지 한번에 동적 할당을 한다. 동적 할당은 상당히 비싼 연산이기 때문에 두개 합친 크기로 한번 할당하는 것이 훨씬 빠르다.

 

A* a = new A();
std::shared_ptr<A> pa1(a);
std::shared_ptr<A> pa2(a);

 

코드를 위와 같이 작성하면 두개의 제어 블록이 따로 생성된다. 그래서 p1이 소멸하면 가리키는 객체 A를 소멸 시키기 때문에 p2가 소멸할 때 이미 해제된 객체를 소멸시키며 오류가 발생한다. 그래서 주소값을 통해 shared_ptr을 생성하는 것을 지양해야 한다.

 

 

class A : public std::enable_shared_from_this<A>
 std::shared_ptr<A> pa2 = pa1->get_shared_ptr();

 

this를 사용해서 shared_ptr을 만들고 싶다면 make_shared<A>(this)는 위와 같이 두 개의 제어블록을 생성하기 때문에 enable_shared_from_this를 상속받아 get_shared_ptr()로 만들어줘야 한다.

'C++' 카테고리의 다른 글

[C++] weak_ptr  (0) 2022.02.24
[C++] override 지정자  (0) 2022.02.22
[C++] 스마트 포인터, unique_ptr  (0) 2022.02.18
[C++] 파일 입출력 - fopen_s, fread, fwrite  (0) 2022.01.25
[C++] 가변 인자 템플릿 (variadic template)  (0) 2022.01.22