memory_shared_ptr

memory_shared_ptr (std::shared_ptr)

<memory> 헤더에 정의되어 있어요. 포인터를 통해 객체의 공유 소유권을 유지하는 스마트 포인터예요. 여러 shared_ptr 객체가 같은 객체를 소유할 수 있어요. 객체는 소유한 shared_ptr이 마지막으로 파괴되거나, operator=·reset()으로 다른 포인터를 대입할 때 파괴되고 메모리가 해제돼요. C++11부터 도입됐어요.

출처: cppreference

본문

template< class T > class shared_ptr;

(C++11부터)

std::shared_ptr은 포인터를 통해 객체의 공유 소유권을 유지하는 스마트 포인터예요. 여러 shared_ptr 객체가 같은 객체를 소유할 수 있어요. 다음 중 하나가 일어날 때 객체가 파괴되고 그 메모리가 해제돼요.

  • 객체를 소유하는 마지막 shared_ptr이 파괴될 때.
  • 객체를 소유하는 마지막 shared_ptroperator=reset()으로 다른 포인터를 대입받을 때.

객체는 delete-표현식 또는 구성 시 shared_ptr에 제공된 커스텀 삭제자를 사용해 파괴돼요.

shared_ptr은 한 객체의 소유권을 공유하면서 다른 객체를 가리키는 포인터를 저장할 수 있어요. 이 기능은 어떤 객체를 소유하면서 그 객체에 속한 멤버 객체를 가리키는 데 쓸 수 있어요. 저장된 포인터는 get()·역참조·비교 연산자가 접근하는 것이고, 관리되는 포인터는 use count가 0이 될 때 삭제자에 전달되는 것이에요.

shared_ptr은 객체를 소유하지 않을 수도 있는데, 이 경우 empty라고 불러요. 모든 shared_ptr 특수화는 CopyConstructible·CopyAssignable·LessThanComparable을 만족하고 bool로 문맥적 변환이 가능해요.

모든 멤버 함수(복사 생성자·복사 대입 포함)는 같은 객체의 소유권을 공유하는 복사본들이더라도 서로 다른 shared_ptr 객체에서 동기화 없이 여러 스레드가 호출할 수 있어요. 같은 shared_ptr 객체를 동기화 없이 접근하고 그 중 하나라도 비-const 멤버 함수를 쓰면 데이터 경쟁이 발생하며, std::atomic<shared_ptr>로 막을 수 있어요.

멤버 타입

  • element_type: T(C++17까지), std::remove_extent_t<T>(C++17부터)
  • weak_type (C++17): std::weak_ptr<T>

멤버 함수

  • (생성자): 새 shared_ptr 생성
  • (소멸자): 더 이상 연결된 shared_ptr이 없으면 소유한 객체 파괴
  • operator=: shared_ptr 대입
  • reset: 관리 객체 교체
  • swap: 관리 객체 맞바꾸기
  • get: 저장된 포인터 반환
  • operator*/operator->: 저장된 포인터 역참조
  • operator[] (C++17): 저장된 배열에 인덱스 접근
  • use_count: 같은 관리 객체를 참조하는 shared_ptr 수 반환
  • operator bool: 저장된 포인터가 비-널인지
  • owner_before: 소유자 기반 순서 제공
  • owner_hash (C++26), owner_equal (C++26)

비멤버 함수

make_shared/make_shared_for_overwrite, allocate_shared/allocate_shared_for_overwrite, static/dynamic/const/reinterpret_pointer_cast, get_deleter, 비교 연산자, operator<<, std::swap 특수화, 원자 접근 함수 등이 있어요.

주의 (Notes)

  • 객체의 소유권은 그 값을 다른 shared_ptr에 복사 생성·복사 대입하는 경우에만 공유할 수 있어요. 다른 shared_ptr이 소유한 원시 포인터로 새 shared_ptr을 만들면 미정의 동작이에요.
  • T는 불완전 타입일 수 있어요. 단 원시 포인터 생성자와 reset(Y*)는 완전 타입에 대한 포인터로만 호출할 수 있어요.
  • T는 함수 타입일 수도 있어요. 이 경우 함수 포인터를 관리하며, 동적 라이브러리·플러그인이 함수 중 하나라도 참조되는 동안 로드된 상태를 유지하는 데 쓰이기도 해요.

구현 참고 (Implementation notes)

일반적 구현에서 shared_ptr은 두 포인터만 보유해요. 저장된 포인터(get()이 반환)와 제어 블록에 대한 포인터요. 제어 블록은 관리 객체에 대한 포인터 또는 관리 객체 자체, 타입 지움된 삭제자, 타입 지움된 할당자, 객체를 소유하는 shared_ptr 수, 객체를 참조하는 weak_ptr 수를 보유하는 동적 할당 객체예요.

더 알아보기 (Learn more)

cppreference