home | help
std::shared_ptr(3)	       C++ Standard Libary	      std::shared_ptr(3)

NAME
     std::shared_ptr - std::shared_ptr

Synopsis
	Defined in header <memory>
	template< class T > class shared_ptr;  (since C++11)

	std::shared_ptr  is  a smart pointer that retains shared ownership of an
     object
	through a pointer. Several shared_ptr objects may own the  same  object.
     The object is
	destroyed  and	its memory deallocated when either of the following hap-
     pens:

	  * the last remaining shared_ptr owning the object is destroyed;
	  * the last remaining shared_ptr owning the object is assigned  another
     pointer via
	    operator= or reset().

	The object is destroyed using delete-expression or a custom deleter that
     is supplied
	to shared_ptr during construction.

	A shared_ptr can share ownership of an object while storing a pointer to
     another
	object. This feature can be used to point to member objects while owning
     the object
	they  belong  to.  The	stored pointer is the one accessed by get(), the
     dereference and
	the comparison operators. The managed pointer is the one passed  to  the
     deleter when
	use count reaches zero.

	A  shared_ptr  may also own no objects, in which case it is called empty
     (an empty
	shared_ptr may have a non-null stored pointer if the aliasing  construc-
     tor was used
	to create it).

	All  specializations  of  shared_ptr  meet  the requirements of CopyCon-
     structible,
	CopyAssignable, and LessThanComparable and are contextually  convertible
     to bool.

	All  member  functions	(including copy constructor and copy assignment)
     can be called
	by multiple threads on different shared_ptr objects without additional
	synchronization even if these objects are copies and share ownership  of
     the same
	object.  If multiple threads of execution access the same shared_ptr ob-
     ject without
	synchronization and any of those accesses uses a non-const member  func-
     tion of
	shared_ptr  then a data race will occur; the std::atomic<shared_ptr> can
     be used to
	prevent the data race.

Member types
	Member type		Definition
	element_type		T			(until C++17)
				std::remove_extent_t<T> (since C++17)
	weak_type (since C++17) std::weak_ptr<T>

Member functions
	constructor   constructs new shared_ptr
		      (public member function)
	destructor    destructs the owned object if no more shared_ptrs link  to
     it
		      (public member function)
	operator=     assigns the shared_ptr
		      (public member function)

Modifiers
	reset	      replaces the managed object
		      (public member function)
	swap	      swaps the managed objects
		      (public member function)

Observers
	get	      returns the stored pointer
		      (public member function)
	operator*     dereferences the stored pointer
	operator->    (public member function)
	operator[]    provides indexed access to the stored array
	(C++17)       (public member function)
		      returns  the number of shared_ptr objects referring to the
     same managed
	use_count     object
		      (public member function)
	unique	      checks whether the managed object is managed only  by  the
     current
	(until C++20) shared_ptr object
		      (public member function)
	operator bool checks if the stored pointer is not null
		      (public member function)
	owner_before  provides owner-based ordering of shared pointers
		      (public member function)
	owner_hash    provides owner-based hashing of shared pointers
	(C++26)       (public member function)
	owner_equal   provides owner-based equal comparison of shared pointers
	(C++26)       (public member function)

Non-member functions
	make_shared		       creates	a  shared pointer that manages a
     new object
	make_shared_for_overwrite     (function template)
	(C++20)
	allocate_shared 	      creates a shared pointer	that  manages  a
     new object
	allocate_shared_for_overwrite allocated using an allocator
	(C++20) 		      (function template)
	static_pointer_cast
	dynamic_pointer_cast		 applies    static_cast,   dynamic_cast,
     const_cast, or
	const_pointer_cast	      reinterpret_cast to the stored pointer
	reinterpret_pointer_cast      (function template)
	(C++17)
	get_deleter		      returns the deleter of specified type,  if
     owned
				      (function template)
	operator==
	operator!=
	operator<
	operator<=
	operator>
	operator>=		       compares  with another shared_ptr or with
     nullptr
	operator<=>		      (function template)
	(removed in C++20)
	(removed in C++20)
	(removed in C++20)
	(removed in C++20)
	(removed in C++20)
	(C++20)
				      outputs the value of the stored pointer to
     an output
	operator<<(std::shared_ptr)   stream
				      (function template)
	std::swap(std::shared_ptr)    specializes the std::swap algorithm
	(C++11) 		      (function template)

	std::atomic_is_lock_free(std::shared_ptr)
	std::atomic_load(std::shared_ptr)
	std::atomic_load_explicit(std::shared_ptr)
	std::atomic_store(std::shared_ptr)
	std::atomic_store_explicit(std::shared_ptr)			special-
     izes atomic
	std::atomic_exchange(std::shared_ptr)			      operations
     for
	std::atomic_exchange_explicit(std::shared_ptr)
     std::shared_ptr
	std::atomic_compare_exchange_weak(std::shared_ptr)	       (function
     template)
	std::atomic_compare_exchange_strong(std::shared_ptr)
	std::atomic_compare_exchange_weak_explicit(std::shared_ptr)
	std::atomic_compare_exchange_strong_explicit(std::shared_ptr)
	(deprecated in C++20)
	(removed in C++26)

Helper classes
	std::atomic<std::shared_ptr> atomic shared pointer
	(C++20) 		     (class template specialization)
	std::hash<std::shared_ptr>   hash support for std::shared_ptr
	(C++11) 		     (class template specialization)

	Deduction guides (since C++17)

Notes
	The ownership of an object can only be shared with another shared_ptr by
     copy
	constructing or copy assigning its value  to  another  shared_ptr.  Con-
     structing a new
	shared_ptr  using the raw underlying pointer owned by another shared_ptr
     leads to
	undefined behavior.

	std::shared_ptr may be used with an incomplete type T. However, the con-
     structor from
	a raw pointer (template<class Y> shared_ptr(Y*)) and the  template<class
     Y> void
	reset(Y*)  member  function  may only be called with a pointer to a com-
     plete type (note
	that std::unique_ptr may be constructed from a raw pointer to an  incom-
     plete type).

	The T in std::shared_ptr<T> may be a function type: in this case it man-
     ages a
	pointer  to  function,	rather than an object pointer. This is sometimes
     used to keep a
	dynamic library or a plugin loaded as long as any of its  functions  are
     referenced:

      void del(void(*)()) {}

      void fun() {}

      int main()
      {
	  std::shared_ptr<void()> ee(fun, del);
	  (*ee)();
      }

Implementation notes
	In a typical implementation, shared_ptr holds only two pointers:

	  * the stored pointer (one returned by get());
	  * a pointer to control block.

	The control block is a dynamically-allocated object that holds:

	  * either a pointer to the managed object or the managed object itself;
	  * the deleter (type-erased);
	  * the allocator (type-erased);
	  * the number of shared_ptrs that own the managed object;
	  * the number of weak_ptrs that refer to the managed object.

	When  shared_ptr  is  created  by calling std::make_shared or std::allo-
     cate_shared, the
	memory for both the control block and the managed object is created with
     a single
	allocation. The managed object is constructed in-place in a data  member
     of the
	control block. When shared_ptr is created via one of the shared_ptr con-
     structors,
	the  managed  object and the control block must be allocated separately.
     In this case,
	the control block stores a pointer to the managed object.

	The pointer held by the shared_ptr  directly  is  the  one  returned  by
     get(), while the
	pointer/object held by the control block is the one that will be deleted
     when the
	number of shared owners reaches zero. These pointers are not necessarily
     equal.

	The  destructor  of shared_ptr decrements the number of shared owners of
     the control
	block. If that counter reaches zero, the control  block  calls	the  de-
     structor of the
	managed  object.  The control block does not deallocate itself until the
     std::weak_ptr
	counter reaches zero as well.

	In existing implementations, the number of weak pointers is  incremented
     ([1], [2])
	if there is a shared pointer to the same control block.

	To  satisfy thread safety requirements, the reference counters are typi-
     cally
	incremented using an equivalent of std::atomic::fetch_add with
	std::memory_order_relaxed (decrementing requires  stronger  ordering  to
     safely destroy
	the control block).

Example
     // Run this code

      #include <chrono>
      #include <iostream>
      #include <memory>
      #include <mutex>
      #include <thread>

      using namespace std::chrono_literals;

      struct Base
      {
	  Base() { std::cout << "Base::Base()\n"; }

	  // Note: non-virtual destructor is OK here
	  ~Base() { std::cout << "Base::~Base()\n"; }
      };

      struct Derived : public Base
      {
	  Derived() { std::cout << "Derived::Derived()\n"; }

	  ~Derived() { std::cout << "Derived::~Derived()\n"; }
      };

      void print(auto rem, std::shared_ptr<Base> const& sp)
      {
	  std::cout << rem << "\n\tget() = " << sp.get()
		    << ", use_count() = " << sp.use_count() << '\n';
      }

      void thr(std::shared_ptr<Base> p)
      {
	  std::this_thread::sleep_for(987ms);
	  std::shared_ptr<Base> lp = p; // thread-safe, even though the
					// shared use_count is incremented
	  {
	      static std::mutex io_mutex;
	      std::lock_guard<std::mutex> lk(io_mutex);
	      print("Local pointer in a thread:", lp);
	  }
      }

      int main()
      {
	  std::shared_ptr<Base> p = std::make_shared<Derived>();

	  print("Created a shared Derived (as a pointer to Base)", p);

	  std::thread t1{thr, p}, t2{thr, p}, t3{thr, p};
	  p.reset(); // release ownership from main

	  print("Shared  ownership between 3 threads and released ownership from
     main:", p);

	  t1.join();
	  t2.join();
	  t3.join();

	  std::cout << "All threads completed, the last one deleted Derived.\n";
      }

Possible output:
      Base::Base()
      Derived::Derived()
      Created a shared Derived (as a pointer to Base)
	      get() = 0x118ac30, use_count() = 1
      Shared ownership between 3 threads and released ownership from main:
	      get() = 0, use_count() = 0
      Local pointer in a thread:
	      get() = 0x118ac30, use_count() = 5
      Local pointer in a thread:
	      get() = 0x118ac30, use_count() = 4
      Local pointer in a thread:
	      get() = 0x118ac30, use_count() = 2
      Derived::~Derived()
      Base::~Base()
      All threads completed, the last one deleted Derived.

Example
     // Run this code

      #include <iostream>
      #include <memory>

      struct MyObj
      {
	  MyObj() { std::cout << "MyObj constructed\n"; }

	  ~MyObj() { std::cout << "MyObj destructed\n"; }
      };

      struct Container : std::enable_shared_from_this<Container> // note: public
     inheritance
      {
	  std::shared_ptr<MyObj> memberObj;

	  void CreateMember() { memberObj = std::make_shared<MyObj>(); }

	  std::shared_ptr<MyObj> GetAsMyObj()
	  {
	      // Use an alias shared ptr for member
	      return	 std::shared_ptr<MyObj>(shared_from_this(),	 member-
     Obj.get());
	  }
      };

      #define COUT(str) std::cout << '\n' << str << '\n'

      #define  DEMO(...)  std::cout  <<  #__VA_ARGS__ << " = " << __VA_ARGS__ <<
     '\n'

      int main()
      {
	  COUT("Creating shared container");
	  std::shared_ptr<Container> cont = std::make_shared<Container>();
	  DEMO(cont.use_count());
	  DEMO(cont->memberObj.use_count());

	  COUT("Creating member");
	  cont->CreateMember();
	  DEMO(cont.use_count());
	  DEMO(cont->memberObj.use_count());

	  COUT("Creating another shared container");
	  std::shared_ptr<Container> cont2 = cont;
	  DEMO(cont.use_count());
	  DEMO(cont->memberObj.use_count());
	  DEMO(cont2.use_count());
	  DEMO(cont2->memberObj.use_count());

	  COUT("GetAsMyObj");
	  std::shared_ptr<MyObj> myobj1 = cont->GetAsMyObj();
	  DEMO(myobj1.use_count());
	  DEMO(cont.use_count());
	  DEMO(cont->memberObj.use_count());
	  DEMO(cont2.use_count());
	  DEMO(cont2->memberObj.use_count());

	  COUT("Copying alias obj");
	  std::shared_ptr<MyObj> myobj2 = myobj1;
	  DEMO(myobj1.use_count());
	  DEMO(myobj2.use_count());
	  DEMO(cont.use_count());
	  DEMO(cont->memberObj.use_count());
	  DEMO(cont2.use_count());
	  DEMO(cont2->memberObj.use_count());

	  COUT("Resetting cont2");
	  cont2.reset();
	  DEMO(myobj1.use_count());
	  DEMO(myobj2.use_count());
	  DEMO(cont.use_count());
	  DEMO(cont->memberObj.use_count());

	  COUT("Resetting myobj2");
	  myobj2.reset();
	  DEMO(myobj1.use_count());
	  DEMO(cont.use_count());
	  DEMO(cont->memberObj.use_count());

	  COUT("Resetting cont");
	  cont.reset();
	  DEMO(myobj1.use_count());
	  DEMO(cont.use_count());
      }

Output:
      Creating shared container
      cont.use_count() = 1
      cont->memberObj.use_count() = 0

      Creating member
      MyObj constructed
      cont.use_count() = 1
      cont->memberObj.use_count() = 1

      Creating another shared container
      cont.use_count() = 2
      cont->memberObj.use_count() = 1
      cont2.use_count() = 2
      cont2->memberObj.use_count() = 1

      GetAsMyObj
      myobj1.use_count() = 3
      cont.use_count() = 3
      cont->memberObj.use_count() = 1
      cont2.use_count() = 3
      cont2->memberObj.use_count() = 1

      Copying alias obj
      myobj1.use_count() = 4
      myobj2.use_count() = 4
      cont.use_count() = 4
      cont->memberObj.use_count() = 1
      cont2.use_count() = 4
      cont2->memberObj.use_count() = 1

      Resetting cont2
      myobj1.use_count() = 3
      myobj2.use_count() = 3
      cont.use_count() = 3
      cont->memberObj.use_count() = 1

      Resetting myobj2
      myobj1.use_count() = 2
      cont.use_count() = 2
      cont->memberObj.use_count() = 1

      Resetting cont
      myobj1.use_count() = 1
      cont.use_count() = 0
      MyObj destructed

See also
	unique_ptr smart pointer with unique object ownership semantics
	(C++11)    (class template)
	weak_ptr   weak reference to an object managed by std::shared_ptr
	(C++11)    (class template)

http://cppreference.com 	   2024.06.10		      std::shared_ptr(3)

home | help