delete px.get()shared_ptr instancesshared_ptr as aCopyConstructible mutex lockSmart pointers are objects which store pointers to dynamically allocated (heap) objects.They behave much like built-in C++ pointers except that they automatically delete the objectpointed to at the appropriate time. Smart pointers are particularly useful in the face ofexceptions as they ensure proper destruction of dynamically allocated objects. They can also beused to keep track of dynamically allocated objects shared by multiple owners.
Conceptually, smart pointers are seen as owning the object pointed to, and thus responsible fordeletion of the object when it is no longer needed. As such, they are examples of the "resourceacquisition is initialization" idiom described in Bjarne Stroustrup’s "The C++ Programming Language",3rd edition, Section 14.4, Resource Management.
This library provides six smart pointer class templates:
scoped_ptr, used to contain ownership of a dynamically allocated object to the current scope;
scoped_array, which provides scoped ownership for a dynamically allocated array;
shared_ptr, a versatile tool for managing shared ownership of an object or array;
weak_ptr, a non-owning observer to a shared_ptr-managed object that can be promoted temporarily to shared_ptr;
intrusive_ptr, a pointer to objects with an embedded reference count;
local_shared_ptr, providing shared ownership within a single thread.
shared_ptr andweak_ptr are part of the C++ standard since its 2011 iteration.
In addition, the library contains the following supporting utility functions and classes:
make_shared, a factory function for creating objects that returns ashared_ptr;
make_unique, a factory function returningstd::unique_ptr;
enable_shared_from_this, a helper base class that enables the acquisition of ashared_ptr pointing tothis;
pointer_to_other, a helper trait for converting one smart pointer type to another;
static_pointer_cast and companions, generic smart pointer casts;
intrusive_ref_counter, a helper base class containing a reference count.
atomic_shared_ptr, a helper class implementing the interface ofstd::atomic for a value of typeshared_ptr.
As a general rule, the destructor oroperator delete for an object managed by pointers in the libraryare not allowed to throw exceptions.
Thescoped_ptr class template stores a pointer to a dynamically allocated object.(Dynamically allocated objects are allocated with the C++new expression.) Theobject pointed to is guaranteed to be deleted, either on destruction of thescoped_ptr,or via an explicitreset. See theexample.
scoped_ptr is a simple solution for simple needs. It supplies a basic "resource acquisitionis initialization" facility, without shared-ownership or transfer-of-ownership semantics.Both its name and enforcement of semantics (by being noncopyable) signal its intent to retainownership solely within the current scope. Because it is noncopyable, it is safer thanshared_ptrfor pointers which should not be copied.
Becausescoped_ptr is simple, in its usual implementation every operation is as fast as for abuilt-in pointer and it has no more space overhead that a built-in pointer.
scoped_ptr cannot be used in C++ Standard Library containers. Useshared_ptr orstd::unique_ptrif you need a smart pointer that can.
scoped_ptr cannot correctly hold a pointer to a dynamically allocated array. Seescoped_array for that usage.
The class template is parameterized onT, the type of the object pointed to. DestroyingT must not thow exceptions,andT must be complete at the pointscoped_ptr<T>::~scoped_ptr is instantiated.
scoped_ptr is defined in<boost/smart_ptr/scoped_ptr.hpp>.
namespace boost { template<class T> class scoped_ptr { private: scoped_ptr(scoped_ptr const&); scoped_ptr& operator=(scoped_ptr const&); void operator==(scoped_ptr const&) const; void operator!=(scoped_ptr const&) const; public: typedef T element_type; explicit scoped_ptr(T * p = 0) noexcept; ~scoped_ptr() noexcept; void reset(T * p = 0) noexcept; T & operator*() const noexcept; T * operator->() const noexcept; T * get() const noexcept; explicit operator bool() const noexcept; void swap(scoped_ptr & b) noexcept; }; template<class T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) noexcept; template<class T> bool operator==( scoped_ptr<T> const & p, std::nullptr_t ) noexcept; template<class T> bool operator==( std::nullptr_t, scoped_ptr<T> const & p ) noexcept; template<class T> bool operator!=( scoped_ptr<T> const & p, std::nullptr_t ) noexcept; template<class T> bool operator!=( std::nullptr_t, scoped_ptr<T> const & p ) noexcept;}typedef T element_type;
Provides the type of the stored pointer.
explicit scoped_ptr(T * p = 0) noexcept;
Constructs ascoped_ptr, storing a copy ofp, which must have been allocated via aC++new expression or be 0.T is not required be a complete type.
~scoped_ptr() noexcept;
Destroys the object pointed to by the stored pointer, if any, as if by usingdelete this->get().T must be a complete type.
void reset(T * p = 0) noexcept;
Deletes the object pointed to by the stored pointer and then stores a copy ofp, which must have been allocated via a C++new expression or be 0.
Since the previous object needs to be deleted,T must be a complete type.
T & operator*() const noexcept;
Returns a reference to the object pointed to by the stored pointer. Behavior is undefined if the stored pointer is 0.
T * operator->() const noexcept;
Returns the stored pointer. Behavior is undefined if the stored pointer is 0.
T * get() const noexcept;
Returns the stored pointer.T need not be a complete type.
explicit operator bool () const noexcept; // never throws
Returnsget() != 0.
Note | On C++03 compilers, the return value is of an unspecified type. |
void swap(scoped_ptr & b) noexcept;
Exchanges the contents of the two smart pointers.T need not be a complete type.
template<class T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) noexcept;
Equivalent toa.swap(b).
template<class T> bool operator==( scoped_ptr<T> const & p, std::nullptr_t ) noexcept;
template<class T> bool operator==( std::nullptr_t, scoped_ptr<T> const & p ) noexcept;
Returnsp.get() == nullptr.
template<class T> bool operator!=( scoped_ptr<T> const & p, std::nullptr_t ) noexcept;
template<class T> bool operator!=( std::nullptr_t, scoped_ptr<T> const & p ) noexcept;
Returnsp.get() != nullptr.
Here’s an example that usesscoped_ptr.
#include <boost/scoped_ptr.hpp>#include <iostream>struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };class MyClass { boost::scoped_ptr<int> ptr; public: MyClass() : ptr(new int) { *ptr = 0; } int add_one() { return ++*ptr; }};int main(){ boost::scoped_ptr<Shoe> x(new Shoe); MyClass my_instance; std::cout << my_instance.add_one() << '\n'; std::cout << my_instance.add_one() << '\n';}The example program produces the beginning of a child’s nursery rhyme:
12Buckle my shoeThe primary reason to usescoped_ptr rather thanstd::auto_ptr orstd::unique_ptr is to let readers of your codeknow that you intend "resource acquisition is initialization" to be applied only for the current scope, and have no intent to transfer ownership.
A secondary reason to usescoped_ptr is to prevent a later maintenance programmer from adding a function that transfersownership by returning theauto_ptr, because the maintenance programmer sawauto_ptr, and assumed ownership could safely be transferred.
Think ofbool vsint. We all know that under the coversbool is usually just anint. Indeed, some argued against including bool in the C++standard because of that. But by codingbool rather thanint, you tell your readers what your intent is. Same withscoped_ptr; by using it you are signaling intent.
It has been suggested thatscoped_ptr<T> is equivalent tostd::auto_ptr<T> const. Ed Brey pointed out, however, thatreset will not work on astd::auto_ptr<T> const.
One common usage ofscoped_ptr is to implement a handle/body (also called pimpl) idiom which avoids exposing the body (implementation) in the header file.
Thescoped_ptr_example_test.cpp sample program includes a header file,scoped_ptr_example.hpp, which uses ascoped_ptr<> to an incomplete type to hide theimplementation. The instantiation of member functions which require a complete type occurs in thescoped_ptr_example.cppimplementation file.
Why doesn’tscoped_ptr have arelease() member?
When reading source code, it is valuable to be able to draw conclusions about program behavior based on the types being used. Ifscoped_ptr had arelease() member,it would become possible to transfer ownership of the held pointer, weakening its role as a way of limiting resource lifetime to a given context. Usestd::auto_ptr wheretransfer of ownership is required. (supplied by Dave Abrahams)
Thescoped_array class template stores a pointer to a dynamically allocated array.(Dynamically allocated arrays are allocated with the C++new[] expression.) The arraypointed to is guaranteed to be deleted, either on destruction of thescoped_array,or via an explicitreset.
Thescoped_array template is a simple solution for simple needs. It supplies a basic"resource acquisition is initialization" facility, without shared-ownership ortransfer-of-ownership semantics. Both its name and enforcement of semantics(by being noncopyable) signal its intent to retain ownership solely within the current scope.Because it is noncopyable, it is safer thanshared_ptr<T[]> for pointers which should not be copied.
Becausescoped_array is so simple, in its usual implementation every operation is as fast as abuilt-in array pointer and it has no more space overhead that a built-in array pointer.
It cannot be used in C++ standard library containers. Seeshared_ptr<T[]> ifscoped_arraydoes not meet your needs.
It cannot correctly hold a pointer to a single object. Seescoped_ptr for that usage.
std::vector is an alternative toscoped_array that is a bit heavier duty but far more flexible.boost::array is an alternative that does not use dynamic allocation.
The class template is parameterized onT, the type of the object pointed to.
scoped_array is defined in<boost/smart_ptr/scoped_array.hpp>.
namespace boost { template<class T> class scoped_array { private: scoped_array(scoped_array const &); scoped_array & operator=(scoped_array const &); void operator==( scoped_array const& ) const; void operator!=( scoped_array const& ) const; public: typedef T element_type; explicit scoped_array(T * p = 0) noexcept; ~scoped_array() noexcept; void reset(T * p = 0) noexcept; T & operator[](std::ptrdiff_t i) const noexcept; T * get() const noexcept; explicit operator bool () const noexcept; void swap(scoped_array & b) noexcept; }; template<class T> void swap(scoped_array<T> & a, scoped_array<T> & b) noexcept; template<class T> bool operator==( scoped_array<T> const & p, std::nullptr_t ) noexcept; template<class T> bool operator==( std::nullptr_t, scoped_array<T> const & p ) noexcept; template<class T> bool operator!=( scoped_array<T> const & p, std::nullptr_t ) noexcept; template<class T> bool operator!=( std::nullptr_t, scoped_array<T> const & p ) noexcept;}typedef T element_type;
Provides the type of the stored pointer.
explicit scoped_array(T * p = 0) noexcept;
Constructs ascoped_array, storing a copy ofp, which must have beenallocated via a C++new[] expression or be 0.T is not required be a complete type.
~scoped_array() noexcept;
Deletes the array pointed to by the stored pointer. Note thatdelete[] on a pointer witha value of 0 is harmless.T must be complete, anddelete[] on the stored pointer mustnot throw exceptions.
void reset(T * p = 0) noexcept;
Deletes the array pointed to by the stored pointer and then stores a copy ofp,which must have been allocated via a C++new[] expression or be 0.T must be complete,anddelete[] on the stored pointer must not throw exceptions.
T & operator[](std::ptrdiff_t i) const noexcept;
Returns a reference to elementi of the array pointed to by the stored pointer.Behavior is undefined and almost certainly undesirable if the stored pointer is 0,or ifi is less than 0 or is greater than or equal to the number of elements inthe array.
T * get() const noexcept;
Returns the stored pointer.T need not be a complete type.
explicit operator bool () const noexcept;
Returnsget() != 0.
Note | On C++03 compilers, the return value is of an unspecified type. |
void swap(scoped_array & b) noexcept;
Exchanges the contents of the two smart pointers.T need not be a complete type.
template<class T> void swap(scoped_array<T> & a, scoped_array<T> & b) noexcept;
Equivalent toa.swap(b).
template<class T> bool operator==( scoped_array<T> const & p, std::nullptr_t ) noexcept;
template<class T> bool operator==( std::nullptr_t, scoped_array<T> const & p ) noexcept;
Returnsp.get() == nullptr.
template<class T> bool operator!=( scoped_array<T> const & p, std::nullptr_t ) noexcept;
template<class T> bool operator!=( std::nullptr_t, scoped_array<T> const & p ) noexcept;
Returnsp.get() != nullptr.
Theshared_ptr class template stores a pointer to a dynamically allocated object, typically with a C++new-expression.The object pointed to is guaranteed to be deleted when the lastshared_ptr pointing to it is destroyed or reset.
shared_ptr<X> p1( new X );shared_ptr<void> p2( new int(5) );shared_ptr deletes the exact pointer that has been passed at construction time, complete with its original type, regardlessof the template parameter. In the second example above, whenp2 is destroyed or reset, it will calldelete on the originalint* that has been passed to the constructor, even thoughp2 itself is of typeshared_ptr<void> and stores a pointer oftypevoid*.
Everyshared_ptr meets theCopyConstructible,MoveConstructible,CopyAssignable andMoveAssignable requirements of theC++ Standard Library, and can be used in standard library containers. Comparison operators are supplied so thatshared_ptrworks with the standard library’s associative containers.
Because the implementation uses reference counting, cycles ofshared_ptr instances will not be reclaimed. For example, ifmain()holds ashared_ptr toA, which directly or indirectly holds ashared_ptr back toA,A’s use count will be 2. Destructionof the original `shared_ptr will leaveA dangling with a use count of 1. Useweak_ptr to "break cycles."
The class template is parameterized onT, the type of the object pointed to.shared_ptr and most of its member functions placeno requirements onT; it is allowed to be an incomplete type, orvoid. Member functions that do place additional requirements(constructors,reset) are explicitly documented below.
shared_ptr<T> can be implicitly converted toshared_ptr<U> wheneverT* can be implicitly converted toU*. In particular,shared_ptr<T> is implicitly convertible toshared_ptr<T const>, toshared_ptr<U> whereU is an accessible base ofT,and toshared_ptr<void>.
shared_ptr is now part of the C++11 Standard, asstd::shared_ptr.
Starting with Boost release 1.53,shared_ptr can be used to hold a pointer to a dynamically allocated array. This is accomplishedby using an array type (T[] orT[N]) as the template parameter. There is almost no difference between using an unsized array,T[], and a sized array,T[N]; the latter just enablesoperator[] to perform a range check on the index.
shared_ptr<double[1024]> p1( new double[1024] );shared_ptr<double[]> p2( new double[n] );A simple guideline that nearly eliminates the possibility of memory leaks is: always use a named smart pointer variable to hold the resultofnew. Every occurence of thenew keyword in the code should have the form:
shared_ptr<T> p(new Y);
It is, of course, acceptable to use another smart pointer in place ofshared_ptr above; havingT andY be the same type, or passingarguments to the constructor ofY is also OK.
If you observe this guideline, it naturally follows that you will have no explicitdelete statements;try/catch constructs will be rare.
Avoid using unnamedshared_ptr temporaries to save typing; to see why this is dangerous, consider this example:
void f(shared_ptr<int>, int);int g();void ok(){ shared_ptr<int> p( new int(2) ); f( p, g() );}void bad(){ f( shared_ptr<int>( new int(2) ), g() );}The functionok follows the guideline to the letter, whereasbad constructs the temporaryshared_ptr in place, admitting the possibility ofa memory leak. Since function arguments are evaluated in unspecified order, it is possible fornew int(2) to be evaluated first,g() second,and we may never get to theshared_ptr constructor ifg throws an exception. SeeHerb Sutter’s treatment ofthe issue for more information.
The exception safety problem described above may also be eliminated by using themake_shared orallocate_shared factoryfunctions defined in<boost/smart_ptr/make_shared.hpp>. These factory functions also provide an efficiency benefit by consolidating allocations.
shared_ptr is defined in<boost/smart_ptr/shared_ptr.hpp>.
namespace boost { class bad_weak_ptr: public std::exception; template<class T> class weak_ptr; template<class T> class shared_ptr { public: typedef /*see below*/ element_type; constexpr shared_ptr() noexcept; constexpr shared_ptr(std::nullptr_t) noexcept; template<class Y> explicit shared_ptr(Y * p); template<class Y, class D> shared_ptr(Y * p, D d); template<class Y, class D, class A> shared_ptr(Y * p, D d, A a); template<class D> shared_ptr(std::nullptr_t p, D d); template<class D, class A> shared_ptr(std::nullptr_t p, D d, A a); ~shared_ptr() noexcept; shared_ptr(shared_ptr const & r) noexcept; template<class Y> shared_ptr(shared_ptr<Y> const & r) noexcept; shared_ptr(shared_ptr && r) noexcept; template<class Y> shared_ptr(shared_ptr<Y> && r) noexcept; template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p) noexcept; template<class Y> shared_ptr(shared_ptr<Y> && r, element_type * p) noexcept; template<class Y> explicit shared_ptr(weak_ptr<Y> const & r); template<class Y> explicit shared_ptr(std::auto_ptr<Y> & r); template<class Y> shared_ptr(std::auto_ptr<Y> && r); template<class Y, class D> shared_ptr(std::unique_ptr<Y, D> && r); shared_ptr & operator=(shared_ptr const & r) noexcept; template<class Y> shared_ptr & operator=(shared_ptr<Y> const & r) noexcept; shared_ptr & operator=(shared_ptr const && r) noexcept; template<class Y> shared_ptr & operator=(shared_ptr<Y> const && r) noexcept; template<class Y> shared_ptr & operator=(std::auto_ptr<Y> & r); template<class Y> shared_ptr & operator=(std::auto_ptr<Y> && r); template<class Y, class D> shared_ptr & operator=(std::unique_ptr<Y, D> && r); shared_ptr & operator=(std::nullptr_t) noexcept; void reset() noexcept; template<class Y> void reset(Y * p); template<class Y, class D> void reset(Y * p, D d); template<class Y, class D, class A> void reset(Y * p, D d, A a); template<class Y> void reset(shared_ptr<Y> const & r, element_type * p) noexcept; template<class Y> void reset(shared_ptr<Y> && r, element_type * p) noexcept; T & operator*() const noexcept; // only valid when T is not an array type T * operator->() const noexcept; // only valid when T is not an array type // only valid when T is an array type element_type & operator[](std::ptrdiff_t i) const noexcept; element_type * get() const noexcept; bool unique() const noexcept; long use_count() const noexcept; explicit operator bool() const noexcept; void swap(shared_ptr & b) noexcept; template<class Y> bool owner_before(shared_ptr<Y> const & rhs) const noexcept; template<class Y> bool owner_before(weak_ptr<Y> const & rhs) const noexcept; }; template<class T, class U> bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept; template<class T, class U> bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept; template<class T, class U> bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept; template<class T> bool operator==(shared_ptr<T> const & p, std::nullptr_t) noexcept; template<class T> bool operator==(std::nullptr_t, shared_ptr<T> const & p) noexcept; template<class T> bool operator!=(shared_ptr<T> const & p, std::nullptr_t) noexcept; template<class T> bool operator!=(std::nullptr_t, shared_ptr<T> const & p) noexcept; template<class T> void swap(shared_ptr<T> & a, shared_ptr<T> & b) noexcept; template<class T> typename shared_ptr<T>::element_type * get_pointer(shared_ptr<T> const & p) noexcept; template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r) noexcept; template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r) noexcept; template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r) noexcept; template<class T, class U> shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U> const & r) noexcept; template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p); template<class D, class T> D * get_deleter(shared_ptr<T> const & p) noexcept; template<class T> bool atomic_is_lock_free( shared_ptr<T> const * p ) noexcept; template<class T> shared_ptr<T> atomic_load( shared_ptr<T> const * p ) noexcept; template<class T> shared_ptr<T> atomic_load_explicit( shared_ptr<T> const * p, int ) noexcept; template<class T> void atomic_store( shared_ptr<T> * p, shared_ptr<T> r ) noexcept; template<class T> void atomic_store_explicit( shared_ptr<T> * p, shared_ptr<T> r, int ) noexcept; template<class T> shared_ptr<T> atomic_exchange( shared_ptr<T> * p, shared_ptr<T> r ) noexcept; template<class T> shared_ptr<T> atomic_exchange_explicit( shared_ptr<T> * p, shared_ptr<T> r, int ) noexcept; template<class T> bool atomic_compare_exchange( shared_ptr<T> * p, shared_ptr<T> * v, shared_ptr<T> w ) noexcept; template<class T> bool atomic_compare_exchange_explicit( shared_ptr<T> * p, shared_ptr<T> * v, shared_ptr<T> w, int, int ) noexcept;}typedef ... element_type;element_type isT whenT is not an array type, andU whenT isU[] orU[N].
constexpr shared_ptr() noexcept;constexpr shared_ptr(std::nullptr_t) noexcept;Constructs an emptyshared_ptr.
use_count() == 0 && get() == 0.
template<class Y> explicit shared_ptr(Y * p);Y must be a complete type. The expressiondelete[] p, whenT is an array type, ordelete p, whenT is not an array type,must be well-formed, well-defined, and not throw exceptions. WhenT isU[N],Y(*)[N] must be convertible toT*; whenT isU[],Y(*)[]must be convertible toT*; otherwise,Y* must be convertible toT*.
WhenT is not an array type, constructs ashared_ptr that owns the pointerp. Otherwise, constructs ashared_ptr that ownsp anda deleter of an unspecified type that callsdelete[] p.
use_count() == 1 && get() == p. IfT is not an array type andp is unambiguously convertible toenable_shared_from_this<V>*for someV,p->shared_from_this() returns a copy of*this.
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
If an exception is thrown, the constructor callsdelete[] p, whenT is an array type, ordelete p, whenT is not an array type.
Note | p must be a pointer to an object that was allocated via a C++new expression or be 0. The postcondition that use count is 1 holds even ifpis 0; invokingdelete on a pointer that has a value of 0 is harmless. |
Note | This constructor is a template in order to remember the actual pointer type passed. The destructor will call delete with the same pointer, completewith its original type, even whenT does not have a virtual destructor, or isvoid. |
template<class Y, class D> shared_ptr(Y * p, D d);template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);template<class D> shared_ptr(std::nullptr_t p, D d);template<class D, class A> shared_ptr(std::nullptr_t p, D d, A a);D must beCopyConstructible. The copy constructor and destructor ofD must not throw. The expressiond(p) must be well-formed, well-defined,and not throw exceptions.A must be anAllocator, as described in section Allocator Requirements [allocator.requirements] of the C++ Standard.WhenT isU[N],Y(*)[N] must be convertible toT*; whenT isU[],Y(*)[] must be convertible toT*; otherwise,Y* must be convertible toT*.
Constructs ashared_ptr that owns the pointerp and the deleterd. The constructors taking an allocator a allocate memory using a copy ofa.
use_count() == 1 && get() == p. IfT is not an array type andp is unambiguously convertible toenable_shared_from_this<V>* for someV,p->shared_from_this() returns a copy of*this.
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
If an exception is thrown,d(p) is called.
Note | When the the time comes to delete the object pointed to byp, the stored copy ofd is invoked with the stored copy ofp as an argument. |
Note | Custom deallocators allow a factory function returning ashared_ptr to insulate the user from its memory allocation strategy. Since the deallocatoris not part of the type, changing the allocation strategy does not break source or binary compatibility, and does not require a client recompilation. For example,a "no-op" deallocator is useful when returning ashared_ptr to a statically allocated object, and other variations allow ashared_ptr to be used as a wrapperfor another smart pointer, easing interoperability. |
Note | The requirement that the copy constructor ofD does not throw comes from the pass by value. If the copy constructor throws, the pointer would leak. |
shared_ptr(shared_ptr const & r) noexcept;template<class Y> shared_ptr(shared_ptr<Y> const & r) noexcept;Y* should be convertible toT*.
Ifr is empty, constructs an emptyshared_ptr; otherwise, constructs ashared_ptr that shares ownership withr.
get() == r.get() && use_count() == r.use_count().
shared_ptr(shared_ptr && r) noexcept;template<class Y> shared_ptr(shared_ptr<Y> && r) noexcept;Y* should be convertible toT*.
Move-constructs ashared_ptr fromr.
*this contains the old value ofr.r is empty andr.get() == 0.
template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p) noexcept;constructs ashared_ptr that shares ownership withr and storesp.
get() == p && use_count() == r.use_count().
template<class Y> shared_ptr(shared_ptr<Y> && r, element_type * p) noexcept;Move-constructs ashared_ptr fromr, while storingp instead.
get() == p anduse_count() equals the old count ofr.r is empty andr.get() == 0.
template<class Y> explicit shared_ptr(weak_ptr<Y> const & r);Y* should be convertible toT*.
Constructs ashared_ptr that shares ownership withr and stores a copy of the pointer stored inr.
use_count() == r.use_count().
bad_weak_ptr whenr.use_count() == 0.
If an exception is thrown, the constructor has no effect.
template<class Y> shared_ptr(std::auto_ptr<Y> & r);template<class Y> shared_ptr(std::auto_ptr<Y> && r);Y* should be convertible toT*.
Constructs ashared_ptr, as if by storing a copy ofr.release().
use_count() == 1.
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
If an exception is thrown, the constructor has no effect.
template<class Y, class D> shared_ptr(std::unique_ptr<Y, D> && r);Y* should be convertible toT*.
Whenr.get() == 0, equivalent toshared_ptr();
WhenD is not a reference type, equivalent toshared_ptr(r.release(), r.get_deleter());
Otherwise, equivalent toshared_ptr(r.release(), del), wheredel is a deleter that stores the referencerd returnedfromr.get_deleter() anddel(p) callsrd(p).
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
If an exception is thrown, the constructor has no effect.
~shared_ptr() noexcept;If*this is empty, or shares ownership with anothershared_ptr instance (use_count() > 1), there are no side effects.
Otherwise, if*this owns a pointerp and a deleterd,d(p) is called.
Otherwise,*this owns a pointerp, anddelete p is called.
shared_ptr & operator=(shared_ptr const & r) noexcept;template<class Y> shared_ptr & operator=(shared_ptr<Y> const & r) noexcept;template<class Y> shared_ptr & operator=(std::auto_ptr<Y> & r);Equivalent toshared_ptr(r).swap(*this).
*this.
Note | The use count updates caused by the temporary object construction and destruction are not considered observable side effects,and the implementation is free to meet the effects (and the implied guarantees) via different means, without creating a temporary. |
Note | In particular, in the example: both assignments may be no-ops. |
shared_ptr & operator=(shared_ptr && r) noexcept;template<class Y> shared_ptr & operator=(shared_ptr<Y> && r) noexcept;template<class Y> shared_ptr & operator=(std::auto_ptr<Y> && r);template<class Y, class D> shared_ptr & operator=(std::unique_ptr<Y, D> && r);Equivalent toshared_ptr(std::move(r)).swap(*this).
*this.
shared_ptr & operator=(std::nullptr_t) noexcept;Equivalent toshared_ptr().swap(*this).
*this.
void reset() noexcept;Equivalent toshared_ptr().swap(*this).
template<class Y> void reset(Y * p);Equivalent toshared_ptr(p).swap(*this).
template<class Y, class D> void reset(Y * p, D d);Equivalent toshared_ptr(p, d).swap(*this).
template<class Y, class D, class A> void reset(Y * p, D d, A a);Equivalent toshared_ptr(p, d, a).swap(*this).
template<class Y> void reset(shared_ptr<Y> const & r, element_type * p) noexcept;Equivalent toshared_ptr(r, p).swap(*this).
template<class Y> void reset(shared_ptr<Y> && r, element_type * p) noexcept;Equivalent toshared_ptr(std::move(r), p).swap(*this).
T & operator*() const noexcept;T should not be an array type. The stored pointer must not be 0.
*get().
T * operator->() const noexcept;T should not be an array type. The stored pointer must not be 0.
get().
element_type & operator[](std::ptrdiff_t i) const noexcept;T should be an array type. The stored pointer must not be 0.i >= 0. IfT isU[N],i < N.
get()[i].
element_type * get() const noexcept;The stored pointer.
bool unique() const noexcept;use_count() == 1.
long use_count() const noexcept;The number ofshared_ptr objects,*this included, that share ownership with*this, or 0 when*this is empty.
explicit operator bool() const noexcept;get() != 0.
Note | This conversion operator allowsshared_ptr objects to be used in boolean contexts, likeif(p && p->valid()) {}. |
Note | The conversion tobool is not merely syntactic sugar. It allowsshared_ptr variables to be declared in conditions when usingdynamic_pointer_cast orweak_ptr::lock. |
Note | On C++03 compilers, the return value is of an unspecified type. |
void swap(shared_ptr & b) noexcept;Exchanges the contents of the two smart pointers.
template<class Y> bool owner_before(shared_ptr<Y> const & rhs) const noexcept;template<class Y> bool owner_before(weak_ptr<Y> const & rhs) const noexcept;See the description ofoperator<.
template<class T, class U> bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;a.get() == b.get().
template<class T, class U> bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;a.get() != b.get().
template<class T> bool operator==(shared_ptr<T> const & p, std::nullptr_t) noexcept;template<class T> bool operator==(std::nullptr_t, shared_ptr<T> const & p) noexcept;p.get() == 0.
template<class T> bool operator!=(shared_ptr<T> const & p, std::nullptr_t) noexcept;template<class T> bool operator!=(std::nullptr_t, shared_ptr<T> const & p) noexcept;p.get() != 0.
template<class T, class U> bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;An unspecified value such that
operator< is a strict weak ordering as described in section [lib.alg.sorting] of the C++ standard;
under the equivalence relation defined byoperator<,!(a < b) && !(b < a), twoshared_ptr instancesare equivalent if and only if they share ownership or are both empty.
Note | Allowsshared_ptr objects to be used as keys in associative containers. |
Note | The rest of the comparison operators are omitted by design. |
template<class T> void swap(shared_ptr<T> & a, shared_ptr<T> & b) noexcept;Equivalent toa.swap(b).
template<class T> typename shared_ptr<T>::element_type * get_pointer(shared_ptr<T> const & p) noexcept;p.get().
Note | Provided as an aid to generic programming. Used bymem_fn. |
template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r) noexcept;The expressionstatic_cast<T*>( (U*)0 ) must be well-formed.
shared_ptr<T>( r, static_cast<typename shared_ptr<T>::element_type*>(r.get()) ).
Caution | The seemingly equivalent expressionshared_ptr<T>(static_cast<T*>(r.get())) will eventuallyresult in undefined behavior, attempting to delete the same object twice. |
template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r) noexcept;The expressionconst_cast<T*>( (U*)0 ) must be well-formed.
shared_ptr<T>( r, const_cast<typename shared_ptr<T>::element_type*>(r.get()) ).
template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r) noexcept;The expressiondynamic_cast<T*>( (U*)0 ) must be well-formed.
Whendynamic_cast<typename shared_ptr<T>::element_type*>(r.get()) returns a nonzero valuep,shared_ptr<T>(r, p);
Otherwise,shared_ptr<T>().
template<class T, class U> shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U> const & r) noexcept;The expressionreinterpret_cast<T*>( (U*)0 ) must be well-formed.
shared_ptr<T>( r, reinterpret_cast<typename shared_ptr<T>::element_type*>(r.get()) ).
template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p);os << p.get();.
os.
template<class D, class T> D * get_deleter(shared_ptr<T> const & p) noexcept;If*this owns a deleterd of type (cv-unqualified)D, returns&d; otherwise returns 0.
Note | The function in this section are atomic with respect to the firstshared_ptr argument, identified by*p. Concurrent access to the sameshared_ptr instance is not a data race, if done exclusively by the functions in this section. |
template<class T> bool atomic_is_lock_free( shared_ptr<T> const * p ) noexcept;false.
Note | This implementation is not lock-free. |
template<class T> shared_ptr<T> atomic_load( shared_ptr<T> const * p ) noexcept;template<class T> shared_ptr<T> atomic_load_explicit( shared_ptr<T> const * p, int ) noexcept;*p.
Note | Theint argument is thememory_order, but this implementation does not use it, as it’s lock-based and therefore always sequentially consistent. |
template<class T> void atomic_store( shared_ptr<T> * p, shared_ptr<T> r ) noexcept;template<class T> void atomic_store_explicit( shared_ptr<T> * p, shared_ptr<T> r, int ) noexcept;p->swap(r).
template<class T> shared_ptr<T> atomic_exchange( shared_ptr<T> * p, shared_ptr<T> r ) noexcept;template<class T> shared_ptr<T> atomic_exchange_explicit( shared_ptr<T> * p, shared_ptr<T> r, int ) noexcept;p->swap(r).
The old value of*p.
template<class T> bool atomic_compare_exchange( shared_ptr<T> * p, shared_ptr<T> * v, shared_ptr<T> w ) noexcept;template<class T> bool atomic_compare_exchange_explicit( shared_ptr<T> * p, shared_ptr<T> * v, shared_ptr<T> w, int, int ) noexcept;If*p is equivalent to*v, assignsw to*p, otherwise assigns*p to*v.
true if*p was equivalent to*v,false otherwise.
Twoshared_ptr instances are equivalent if they store the same pointer value andshare ownership.
Seeshared_ptr_example.cpp for a complete example program. The program builds astd::vector andstd::set ofshared_ptr objects.
Note that after the containers have been populated, some of theshared_ptr objects will have a use count of 1 rather thana use count of 2, since the set is astd::set rather than astd::multiset, and thus does not contain duplicate entries.Furthermore, the use count may be even higher at various times whilepush_back andinsert container operations are performed.More complicated yet, the container operations may throw exceptions under a variety of circumstances. Getting the memory managementand exception handling in this example right without a smart pointer would be a nightmare.
One common usage ofshared_ptr is to implement a handle/body (also called pimpl) idiom which avoids exposing the body (implementation)in the header file.
Theshared_ptr_example2_test.cpp sample program includes a header file,shared_ptr_example2.hpp, which uses ashared_ptr to an incomplete type to hide the implementation.The instantiation of member functions which require a complete type occurs in theshared_ptr_example2.cppimplementation file. Note that there is no need for an explicit destructor. Unlike~scoped_ptr,~shared_ptr does not require thatT be a complete type.
shared_ptr objects offer the same level of thread safety as built-in types. Ashared_ptr instance can be "read" (accessed using only const operations)simultaneously by multiple threads. Differentshared_ptr instances can be "written to" (accessed using mutable operations such asoperator= orreset)simultaneously by multiple threads (even when these instances are copies, and share the same reference count underneath.)
Any other simultaneous accesses result in undefined behavior.
Examples:
shared_ptr<int> p(new int(42));shared_ptr from two threads// thread Ashared_ptr<int> p2(p); // reads p// thread Bshared_ptr<int> p3(p); // OK, multiple reads are safeshared_ptr instances from two threads// thread Ap.reset(new int(1912)); // writes p// thread Bp2.reset(); // OK, writes p2shared_ptr from two threads// thread Ap = p3; // reads p3, writes p// thread Bp3.reset(); // writes p3; undefined, simultaneous read/writeshared_ptr from two threads// thread Ap3 = p2; // reads p2, writes p3// thread B// p2 goes out of scope: undefined, the destructor is considered a "write access"shared_ptr from two threads// thread Ap3.reset(new int(1));// thread Bp3.reset(new int(2)); // undefined, multiple writesStarting with Boost release 1.33.0,shared_ptr uses a lock-free implementation on most common platforms.
If your program is single-threaded and does not link to any libraries that might have usedshared_ptr in its default configuration,you can#define the macroBOOST_SP_DISABLE_THREADS on a project-wide basis to switch to ordinary non-atomic reference count updates.
(DefiningBOOST_SP_DISABLE_THREADS in some, but not all, translation units is technically a violation of the One Definition Rule andundefined behavior. Nevertheless, the implementation attempts to do its best to accommodate the request to use non-atomic updates in thosetranslation units. No guarantees, though.)
You can define the macroBOOST_SP_USE_PTHREADS to turn off the lock-free platform-specific implementation and fall back to the genericpthread_mutex_t-based code.
There are several variations of shared pointers, with different tradeoffs; why does the smart pointer library supply only a single implementation? It would be useful to be able to experiment with each type so as to find the most suitable for the job at hand?
An important goal ofshared_ptr is to provide a standard shared-ownership pointer. Having a single pointer type is important for stablelibrary interfaces, since different shared pointers typically cannot interoperate, i.e. a reference counted pointer (used by library A)cannot share ownership with a linked pointer (used by library B.)
Why doesn’t shared_ptr have template parameters supplying traits or policies to allow extensive user customization?
Parameterization discourages users. Theshared_ptr template is carefully crafted to meet common needs without extensive parameterization.
I am not convinced. Default parameters can be used where appropriate to hide the complexity. Again, why not policies?
Template parameters affect the type. See the answer to the first question above.
Why doesn’tshared_ptr use a linked list implementation?
A linked list implementation does not offer enough advantages to offset the added cost of an extra pointer. In addition, it is expensive tomake a linked list implementation thread safe.
Why doesn’tshared_ptr (or any of the other Boost smart pointers) supply an automatic conversion to T*?
Automatic conversion is believed to be too error prone.
Why doesshared_ptr supplyuse_count()?
As an aid to writing test cases and debugging displays. One of the progenitors haduse_count(), and it was useful in tracking down bugs ina complex project that turned out to have cyclic-dependencies.
Why doesn’tshared_ptr specify complexity requirements?
Because complexity requirements limit implementors and complicate the specification without apparent benefit toshared_ptr users. For example,error-checking implementations might become non-conforming if they had to meet stringent complexity requirements.
Why doesn’tshared_ptr provide arelease() function?
shared_ptr cannot give away ownership unless it’sunique() because the other copy will still destroy the object.
Consider:
shared_ptr<int> a(new int);shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2int * p = a.release();// Who owns p now? b will still call delete on it in its destructor.Furthermore, the pointer returned byrelease() would be difficult to deallocate reliably, as the sourceshared_ptr could have been created with acustom deleter, or may have pointed to an object of a different type.
Why isoperator->() const, but its return value is a non-const pointer to the element type?
Shallow copy pointers, including raw pointers, typically don’t propagate constness. It makes little sense for them to do so, as you can always obtain anon-const pointer from a const one and then proceed to modify the object through it.shared_ptr is "as close to raw pointers as possible but no closer".
Theweak_ptr class template stores a "weak reference" to an object that’s already managed by ashared_ptr.To access the object, aweak_ptr can be converted to ashared_ptr using theshared_ptr constructor takingweak_ptr, or theweak_ptr member functionlock. When the lastshared_ptr to the object goes away and theobject is deleted, the attempt to obtain ashared_ptr from theweak_ptr instances that refer to the deletedobject will fail: the constructor will throw an exception of typeboost::bad_weak_ptr, andweak_ptr::lock willreturn an emptyshared_ptr.
Everyweak_ptr meets theCopyConstructible andAssignable requirements of the C++ Standard Library, and socan be used in standard library containers. Comparison operators are supplied so thatweak_ptr works with the standardlibrary’s associative containers.
weak_ptr operations never throw exceptions.
The class template is parameterized onT, the type of the object pointed to.
Compared toshared_ptr,weak_ptr provides a very limited subset of operations since accessing its stored pointer isoften dangerous in multithreaded programs, and sometimes unsafe even within a single thread (that is, it may invoke undefinedbehavior.) Pretend for a moment thatweak_ptr had a get member function that returned a raw pointer, and consider this innocentpiece of code:
shared_ptr<int> p(new int(5));weak_ptr<int> q(p);// some time laterif(int * r = q.get()){ // use *r}Imagine that after theif, but immediately beforer is used, another thread executes the statementp.reset(). Nowr is a dangling pointer.
The solution to this problem is to create a temporaryshared_ptr fromq:
shared_ptr<int> p(new int(5));weak_ptr<int> q(p);// some time laterif(shared_ptr<int> r = q.lock()){ // use *r}Nowr holds a reference to the object that was pointed byq. Even ifp.reset() is executed in another thread, the object will stay alive untilr goes out of scope or is reset. By obtaining ashared_ptr to the object, we have effectively locked it against destruction.
weak_ptr is defined in<boost/smart_ptr/weak_ptr.hpp>.
namespace boost { template<class T> class weak_ptr { public: typedef /*see below*/ element_type; weak_ptr() noexcept; template<class Y> weak_ptr(shared_ptr<Y> const & r) noexcept; weak_ptr(weak_ptr const & r) noexcept; template<class Y> weak_ptr(weak_ptr<Y> const & r) noexcept; weak_ptr(weak_ptr && r) noexcept; ~weak_ptr() noexcept; weak_ptr & operator=(weak_ptr const & r) noexcept; weak_ptr & operator=(weak_ptr && r) noexcept; template<class Y> weak_ptr & operator=(weak_ptr<Y> const & r) noexcept; template<class Y> weak_ptr & operator=(shared_ptr<Y> const & r) noexcept; long use_count() const noexcept; bool expired() const noexcept; shared_ptr<T> lock() const noexcept; void reset() noexcept; void swap(weak_ptr<T> & b) noexcept; template<class Y> bool owner_before( weak_ptr<Y> const & r ) const noexcept; template<class Y> bool owner_before( shared_ptr<Y> const & r ) const noexcept; }; template<class T, class U> bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b) noexcept; template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b) noexcept;}typedef ... element_type;element_type isT whenT is not an array type, andU whenT isU[] orU[N].
weak_ptr() noexcept;Constructs an emptyweak_ptr.
use_count() == 0.
template<class Y> weak_ptr(shared_ptr<Y> const & r) noexcept;weak_ptr(weak_ptr const & r) noexcept;template<class Y> weak_ptr(weak_ptr<Y> const & r) noexcept;Ifr is empty, constructs an emptyweak_ptr; otherwise, constructs aweak_ptr that shares ownership withr as if by storing a copy of the pointer stored inr.
use_count() == r.use_count().
weak_ptr(weak_ptr && r) noexcept;Constructs aweak_ptr that has the valuer held.
r is empty.
~weak_ptr() noexcept;Destroys thisweak_ptr but has no effect on the object its stored pointer points to.
weak_ptr & operator=(weak_ptr const & r) noexcept;weak_ptr & operator=(weak_ptr && r) noexcept;template<class Y> weak_ptr & operator=(weak_ptr<Y> const & r) noexcept;template<class Y> weak_ptr & operator=(shared_ptr<Y> const & r) noexcept;Equivalent toweak_ptr(r).swap(*this).
Note | The implementation is free to meet the effects (and the implied guarantees) via different means, without creating a temporary. |
long use_count() const noexcept;0 if*this is empty; otherwise, the number ofshared_ptr objects that share ownership with*this.
bool expired() const noexcept;use_count() == 0.
shared_ptr<T> lock() const noexcept;expired()? shared_ptr<T>(): shared_ptr<T>(*this).
void reset() noexcept;Equivalent toweak_ptr().swap(*this).
void swap(weak_ptr & b) noexcept;Exchanges the contents of the two smart pointers.
template<class Y> bool owner_before( weak_ptr<Y> const & r ) const noexcept;template<class Y> bool owner_before( shared_ptr<Y> const & r ) const noexcept;See the description ofoperator<.
template<class T, class U> bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b) noexcept;An unspecified value such that
operator< is a strict weak ordering as described in section [lib.alg.sorting] of the C++ standard;
under the equivalence relation defined byoperator<,!(a < b) && !(b < a), twoweak_ptr instancesare equivalent if and only if they share ownership or are both empty.
Note | Allowsweak_ptr objects to be used as keys in associative containers. |
template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b) noexcept;Equivalent toa.swap(b).
Can an object create a weak_ptr to itself in its constructor?
No. Aweak_ptr can only be created from ashared_ptr, and at object construction time noshared_ptr to the object exists yet. Even if you could create a temporaryshared_ptr tothis,it would go out of scope at the end of the constructor, and allweak_ptr instances would instantly expire.
The solution is to make the constructor private, and supply a factory function that returns ashared_ptr:
class X{private: X();public: static shared_ptr<X> create() { shared_ptr<X> px(new X); // create weak pointers from px here return px; }};The function templatesmake_shared andallocate_shared provide convenient,safe and efficient ways to createshared_ptr objects.
Consistent use ofshared_ptr can eliminate the need to use an explicitdelete, but alone it provides no support in avoiding explicitnew. Therewere repeated requests from users for a factory function that creates anobject of a given type and returns ashared_ptr to it. Besides convenienceand style, such a function is also exception safe and considerably fasterbecause it can use a single allocation for both the object and itscorresponding control block, eliminating a significant portion ofshared_ptr construction overhead. This eliminates one of the majorefficiency complaints aboutshared_ptr.
The family of overloaded function templates,make_shared andallocate_shared, were provided to address this need.make_shared uses theglobaloperator new to allocate memory, whereasallocate_shared uses anuser-supplied allocator, allowing finer control.
The rationale for choosing the namemake_shared is that the expressionmake_shared<Widget>() can be read aloud and conveys the intended meaning.
Originally the Boost function templatesallocate_shared andmake_sharedwere provided for scalar objects only. There was a need to have efficientallocation of array objects. One criticism of class templateshared_arraywas always the lack of a utility likemake_shared that uses only a singleallocation. Whenshared_ptr was enhanced to support array types, additionaloverloads ofallocate_shared andmake_shared were provided for arraytypes.
make_shared andallocate_shared are defined in<boost/smart_ptr/make_shared.hpp>.
namespace boost {// only if T is not an array type template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args); template<class T, class A, class... Args> shared_ptr<T> allocate_shared(const A& a, Args&&... args);// only if T is an array type of the form U[] template<class T> shared_ptr<T> make_shared(std::size_t n); template<class T, class A> shared_ptr<T> allocate_shared(const A& a, std::size_t n);// only if T is an array type of the form U[N] template<class T> shared_ptr<T> make_shared(); template<class T, class A> shared_ptr<T> allocate_shared(const A& a);// only if T is an array type of the form U[] template<class T> shared_ptr<T> make_shared(std::size_t n, const remove_extent_t<T>& v); template<class T, class A> shared_ptr<T> allocate_shared(const A& a, std::size_t n, const remove_extent_t<T>& v);// only if T is an array type of the form U[N] template<class T> shared_ptr<T> make_shared(const remove_extent_t<T>& v); template<class T, class A> shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& v);// only if T is not an array type of the form U[] template<class T> shared_ptr<T> make_shared_noinit(); template<class T, class A> shared_ptr<T> allocate_shared_noinit(const A& a);// only if T is an array type of the form U[N] template<class T> shared_ptr<T> make_shared_noinit(std::size_t n); template<class T, class A> shared_ptr<T> allocate_shared_noinit(const A& a, std::size_t n);}The common requirements that apply to allmake_shared andallocate_sharedoverloads, unless specified otherwise, are described below.
A shall be anallocator. The copy constructor and destructorofA shall not throw exceptions.
Allocates memory for an object of typeT orn objects ofU(ifT is an array type of the formU[] andn is determined byarguments, as specified by the concrete overload). The object is initializedfrom arguments as specified by the concrete overload. Uses a rebound copy ofa (for an unspecifiedvalue_type) to allocate memory. If an exception isthrown, the functions have no effect.
Ashared_ptr instance that stores and owns the address of thenewly constructed object.
r.get() != 0 andr.use_count() == 1, whereris the return value.
std::bad_alloc, an exception thrown fromA::allocate, or from theinitialization of the object.
Performs no more than one memory allocation. This provides efficiencyequivalent to an intrusive smart pointer.
When an object of an array type is specified to be initialized to a value ofthe same typev, this shall be interpreted to mean that each array elementof the object is initialized to the corresponding element fromv.
When an object of an array type is specified to be value-initialized, thisshall be interpreted to mean that each array element of the object isvalue-initialized.
When a (sub)object of non-array typeU is specified to be initialized toa valuev, or constructed fromargs...,make_shared shall performthis initialization via the expression::new(p) U(expr) (whereexpr isv orstd::forward<Args>(args)...) respectively) andphas typevoid* and points to storage suitable to hold an object of typeU.
When a (sub)object of non-array typeU is specified to be initialized toa valuev, or constructed fromargs...,allocate_shared shallperform this initialization via the expressionstd::allocator_traits<A2>::construct(a2, p, expr) (whereexpr isv orstd::forward<Args>(args)...) respectively),ppoints to storage suitable to hold an object of typeU, anda2 oftypeA2 is a rebound copya such that itsvalue_type isU.
When a (sub)object of non-array typeU is specified to bedefault-initialized,make_shared_noinit andallocate_shared_noinit shallperform this initialization via the expression::new(p) U, wherep has typevoid* and points to storage suitable to hold an object oftypeU.
When a (sub)object of non-array typeU is specified to bevalue-initialized,make_shared shall perform this initialization via theexpression::new(p) U(), wherep has typevoid* and points tostorage suitable to hold an object of typeU.
When a (sub)object of non-array typeU is specified to bevalue-initialized,allocate_shared shall perform this initialization via theexpressionstd::allocator_traits<A2>::construct(a2, p), wherep points to storage suitable to hold an object of typeU anda2 oftypeA2 is a rebound copy ofa such that its value_type isU.
Array elements are initialized in ascending order of their addresses.
When the lifetime of the object managed by the return value ends, or whenthe initialization of an array element throws an exception, the initializedelements should be destroyed in the reverse order of their construction.
Note | These functions will typically allocate more memory than the total sizeof the element objects to allow for internal bookkeeping structures such asthe reference counts. |
template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args);template<class T, class A, class... Args> shared_ptr<T> allocate_shared(const A& a, Args&&... args);These overloads shall only participate in overload resolution whenT is not an array type.
Ashared_ptr to an object of typeT, constructed fromargs....
auto p = make_shared<int>();
auto p = make_shared<std::vector<int> >(16, 1);
template<class T> shared_ptr<T> make_shared(std::size_t n);template<class T, class A> shared_ptr<T> allocate_shared(const A& a, std::size_t n);These overloads shall only participate in overload resolution whenT is an array type of the formU[].
Ashared_ptr to a sequence ofn value-initialized objects oftypeU.
auto p = make_shared<double[]>(1024);
auto p = make_shared<double[][2][2]>(6);
template<class T> shared_ptr<T> make_shared();template<class T, class A> shared_ptr<T> allocate_shared(const A& a);These overloads shall only participate in overload resolution whenT is an array type of the formU[N].
Ashared_ptr to a sequence ofN value-initialized objects oftypeU.
auto p = make_shared<double[1024]>();
auto p = make_shared<double[6][2][2]>();
template<class T> shared_ptr<T> make_shared(std::size_t n, const remove_extent_t<T>& v);template<class T, class A> shared_ptr<T> allocate_shared(const A& a, std::size_t n, const remove_extent_t<T>& v);These overloads shall only participate in overload resolution whenT is an array type of the formU[].
Ashared_ptr to a sequence ofn objects of typeU, eachinitialized tov.
auto p = make_shared<double[]>(1024, 1.0);
auto p = make_shared<double[][2]>(6, {1.0, 0.0});
auto p = make_shared<std::vector<int>[]>(4, {1, 2});
template<class T> shared_ptr<T> make_shared(const remove_extent_t<T>& v);template<class T, class A> shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& v);These overloads shall only participate in overload resolution whenT is an array type of the formU[N].
Ashared_ptr to a sequence ofN objects of typeU, eachinitialized tov.
auto p = make_shared<double[1024]>(1.0);
auto p = make_shared<double[6][2]>({1.0, 0.0});
auto p = make_shared<std::vector<int>[4]>({1, 2});
template<class T> shared_ptr<T> make_shared_noinit();template<class T, class A> shared_ptr<T> allocate_shared_noinit(const A& a);These overloads shall only participate in overload resolution whenT is not an array type, or an array type of theU[N].
Ashared_ptr to a default-initialized object of typeT, or asequence ofN default-initialized objects of typeU, respectively.
auto p = make_shared_noinit<double[1024]>();
template<class T> shared_ptr<T> make_shared_noinit(std::size_t n);template<class T, class A> shared_ptr<T> allocate_shared_noinit(const A& a, std::size_t n);These overloads shall only participate in overload resolution whenT is an array type of the formU[].
Ashared_ptr to a sequence ofn default-initialized objectsof typeU.
auto p = make_shared_noinit<double[]>(1024);
The class templateenable_shared_from_this is used as a base class that allowsashared_ptr or aweak_ptr to the current object to be obtained from within amember function.
enable_shared_from_this<T> defines two member functions calledshared_from_thisthat return ashared_ptr<T> andshared_ptr<T const>, depending on constness, tothis. It also defines two member functions calledweak_from_this that return acorrespondingweak_ptr.
#include <boost/enable_shared_from_this.hpp>#include <boost/shared_ptr.hpp>#include <cassert>class Y: public boost::enable_shared_from_this<Y>{public: boost::shared_ptr<Y> f() { return shared_from_this(); }};int main(){ boost::shared_ptr<Y> p(new Y); boost::shared_ptr<Y> q = p->f(); assert(p == q); assert(!(p < q || q < p)); // p and q must share ownership}enable_shared_from_this is defined in<boost/smart_ptr/enable_shared_from_this.hpp>.
namespace boost { template<class T> class enable_shared_from_this { private: // exposition only weak_ptr<T> weak_this_; protected: enable_shared_from_this() = default; ~enable_shared_from_this() = default; enable_shared_from_this(const enable_shared_from_this&) noexcept; enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept; public: shared_ptr<T> shared_from_this(); shared_ptr<T const> shared_from_this() const; weak_ptr<T> weak_from_this() noexcept; weak_ptr<T const> weak_from_this() const noexcept; }}enable_shared_from_this(enable_shared_from_this const &) noexcept;Default-constructsweak_this_.
Note | weak_this_ isnot copied from the argument. |
enable_shared_from_this& operator=(enable_shared_from_this const &) noexcept;*this.
Note | weak_this_ is unchanged. |
template<class T> shared_ptr<T> shared_from_this();template<class T> shared_ptr<T const> shared_from_this() const;shared_ptr<T>(weak_this_).
Note | These members throwbad_weak_ptr when*this is not owned by ashared_ptr. |
Note |
the construction of |
template<class T> weak_ptr<T> weak_from_this() noexcept;template<class T> weak_ptr<T const> weak_from_this() const noexcept;weak_this_.
Themake_unique function templates provide convenient and safe ways tocreatestd::unique_ptr objects.
The C++11 standard introducedstd::unique_ptr but did not provide anymake_unique utility likestd::make_shared that provided the sameexception safety and facility to avoid writingnew expressions. Before itwas implemented by some standard library vendors (and prior to the C++14standard introducingstd::make_unique), this library provided it due torequests from users.
This library also provides additional overloads ofmake_unique fordefault-initialization, when users do not need or want to incur the expenseof value-initialization. The C++ standard does not yet provide thisfeature withstd::make_unique.
make_unique is defined in<boost/smart_ptr/make_unique.hpp>.
namespace boost {// only if T is not an array type template<class T, class... Args> std::unique_ptr<T> make_unique(Args&&... args);// only if T is not an array type template<class T> std::unique_ptr<T> make_unique(remove_reference_t<T>&& v);// only if T is an array type of the form U[] template<class T> std::unique_ptr<T> make_unique(std::size_t n);// only if T is not an array type template<class T> std::unique_ptr<T> make_unique_noinit();// only if T is an array type of the form U[] template<class T> std::unique_ptr<T> make_unique_noinit(std::size_t n);}template<class T, class... Args> std::unique_ptr<T> make_unique(Args&&... args);These overloads shall only participate in overload resolution whenT is not an array type.
std::unique_ptr<T>(new T(std::forward<Args>(args)...).
auto p = make_unique<int>();
template<class T> std::unique_ptr<T> make_unique(remove_reference_t<T>&& v);These overloads shall only participate in overload resolution whenT is not an array type.
std::unique_ptr<T>(new T(std::move(v)).
auto p = make_unique<std::vector<int> >({1, 2});
template<class T> std::unique_ptr<T> make_unique(std::size_t n);These overloads shall only participate in overload resolution whenT is an array type of the formU[].
std::unique_ptr<U[]>(new U[n]()).
auto p = make_unique<double[]>(1024);
template<class T> std::unique_ptr<T> make_unique_noinit();These overloads shall only participate in overload resolution whenT is not an array type.
std::unique_ptr<T>(new T).
auto p = make_unique_noinit<double[1024]>();
template<class T> std::unique_ptr<T> make_unique_noinit(std::size_t n);These overloads shall only participate in overload resolution whenT is an array type of the formU[].
std::unique_ptr<U[]>(new U[n]).
auto p = make_unique_noinit<double[]>(1024);
Theintrusive_ptr class template stores a pointer to an object with an embedded reference count.Every newintrusive_ptr instance increments the reference count by using an unqualified call to thefunctionintrusive_ptr_add_ref, passing it the pointer as an argument. Similarly, when anintrusive_ptris destroyed, it callsintrusive_ptr_release; this function is responsible for destroying the object whenits reference count drops to zero. The user is expected to provide suitable definitions of these two functions.On compilers that support argument-dependent lookup,intrusive_ptr_add_ref andintrusive_ptr_release shouldbe defined in the namespace that corresponds to their parameter; otherwise, the definitions need to go in namespaceboost. The library provides a helper base class templateintrusive_ref_counter whichmay help adding support forintrusive_ptr to user types.
The class template is parameterized onT, the type of the object pointed to.intrusive_ptr<T> can be implicitlyconverted tointrusive_ptr<U> wheneverT* can be implicitly converted toU*.
The main reasons to useintrusive_ptr are:
Some existing frameworks or OSes provide objects with embedded reference counts;
The memory footprint ofintrusive_ptr is the same as the corresponding raw pointer;
intrusive_ptr<T> can be constructed from an arbitrary raw pointer of typeT*.
As a general rule, if it isn’t obvious whetherintrusive_ptr better fits your needs thanshared_ptr, try ashared_ptr-based design first.
intrusive_ptr is defined in<boost/smart_ptr/intrusive_ptr.hpp>.
namespace boost { template<class T> class intrusive_ptr { public: typedef T element_type; intrusive_ptr() noexcept; intrusive_ptr(T * p, bool add_ref = true); intrusive_ptr(intrusive_ptr const & r); template<class Y> intrusive_ptr(intrusive_ptr<Y> const & r); ~intrusive_ptr(); intrusive_ptr & operator=(intrusive_ptr const & r); template<class Y> intrusive_ptr & operator=(intrusive_ptr<Y> const & r); intrusive_ptr & operator=(T * r); void reset(); void reset(T * r); void reset(T * r, bool add_ref); T & operator*() const noexcept; T * operator->() const noexcept; T * get() const noexcept; T * detach() noexcept; explicit operator bool () const noexcept; void swap(intrusive_ptr & b) noexept; }; template<class T, class U> bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) noexcept; template<class T, class U> bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) noexcept; template<class T, class U> bool operator==(intrusive_ptr<T> const & a, U * b) noexcept; template<class T, class U> bool operator!=(intrusive_ptr<T> const & a, U * b) noexcept; template<class T, class U> bool operator==(T * a, intrusive_ptr<U> const & b) noexcept; template<class T, class U> bool operator!=(T * a, intrusive_ptr<U> const & b) noexcept; template<class T, class U> bool operator<(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) noexcept; template<class T> void swap(intrusive_ptr<T> & a, intrusive_ptr<T> & b) noexcept; template<class T> T * get_pointer(intrusive_ptr<T> const & p) noexcept; template<class T, class U> intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & r) noexcept; template<class T, class U> intrusive_ptr<T> const_pointer_cast(intrusive_ptr<U> const & r) noexcept; template<class T, class U> intrusive_ptr<T> dynamic_pointer_cast(intrusive_ptr<U> const & r) noexcept; template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, intrusive_ptr<Y> const & p);}typedef T element_type;Provides the type of the template parameter T.
intrusive_ptr() noexcept;get() == 0.
intrusive_ptr(T * p, bool add_ref = true);if(p != 0 && add_ref) intrusive_ptr_add_ref(p);.
get() == p.
intrusive_ptr(intrusive_ptr const & r);template<class Y> intrusive_ptr(intrusive_ptr<Y> const & r);T * p = r.get(); if(p != 0) intrusive_ptr_add_ref(p);.
get() == r.get().
~intrusive_ptr();if(get() != 0) intrusive_ptr_release(get());.
intrusive_ptr & operator=(intrusive_ptr const & r);template<class Y> intrusive_ptr & operator=(intrusive_ptr<Y> const & r);intrusive_ptr & operator=(T * r);Equivalent tointrusive_ptr(r).swap(*this).
*this.
void reset();Equivalent tointrusive_ptr().swap(*this).
void reset(T * r);Equivalent tointrusive_ptr(r).swap(*this).
void reset(T * r, bool add_ref);Equivalent tointrusive_ptr(r, add_ref).swap(*this).
T & operator*() const noexcept;get() != 0.
*get().
T * operator->() const noexcept;get() != 0.
get().
T * get() const noexcept;the stored pointer.
T * detach() noexcept;the stored pointer.
get() == 0.
Note | The returned pointer has an elevated reference count. This allows conversion of anintrusive_ptrback to a raw pointer, without the performance overhead of acquiring and dropping an extra reference.It can be viewed as the complement of the non-reference-incrementing constructor. |
Caution | Usingdetach escapes the safety of automatic reference counting provided byintrusive_ptr.It should by used only where strictly necessary (such as when interfacing to an existing API), and whenthe implications are thoroughly understood. |
explicit operator bool () const noexcept;get() != 0.
Note | This conversion operator allowsintrusive_ptr objects to be used in boolean contexts,likeif (p && p->valid()) {}. |
Note | On C++03 compilers, the return value is of an unspecified type. |
void swap(intrusive_ptr & b) noexcept;Exchanges the contents of the two smart pointers.
template<class T, class U> bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) noexcept;a.get() == b.get().
template<class T, class U> bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) noexcept;a.get() != b.get().
template<class T, class U> bool operator==(intrusive_ptr<T> const & a, U * b) noexcept;a.get() == b.
template<class T, class U> bool operator!=(intrusive_ptr<T> const & a, U * b) noexcept;a.get() != b.
template<class T, class U> bool operator==(T * a, intrusive_ptr<U> const & b) noexcept;a == b.get().
template<class T, class U> bool operator!=(T * a, intrusive_ptr<U> const & b) noexcept;a != b.get().
template<class T, class U> bool operator<(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) noexcept;std::less<T *>()(a.get(), b.get()).
Note | Allowsintrusive_ptr objects to be used as keys in associative containers. |
template<class T> void swap(intrusive_ptr<T> & a, intrusive_ptr<T> & b) noexcept;Equivalent toa.swap(b).
template<class T> T * get_pointer(intrusive_ptr<T> const & p) noexcept;p.get().
Note | Provided as an aid to generic programming. Used bymem_fn. |
template<class T, class U> intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & r) noexcept;intrusive_ptr<T>(static_cast<T*>(r.get())).
template<class T, class U> intrusive_ptr<T> const_pointer_cast(intrusive_ptr<U> const & r) noexcept;intrusive_ptr<T>(const_cast<T*>(r.get())).
template<class T, class U> intrusive_ptr<T> dynamic_pointer_cast(intrusive_ptr<U> const & r) noexcept;intrusive_ptr<T>(dynamic_cast<T*>(r.get())).
template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, intrusive_ptr<Y> const & p);os << p.get();.
os.
Theintrusive_ref_counter class template implements a reference counter fora derived user’s class that is intended to be used withintrusive_ptr. Thebase class has associatedintrusive_ptr_add_ref andintrusive_ptr_releasefunctions which modify the reference counter as needed and destroy the user’sobject when the counter drops to zero.
The class template is parameterized onDerived andCounterPolicyparameters. The first parameter is the user’s class that derives fromintrusive_ref_counter. This type is needed in order to destroy the objectcorrectly when there are no references to it left.
The second parameter is a policy that defines the nature of the referencecounter. The library provides two such policies:thread_unsafe_counter andthread_safe_counter. The former instructs theintrusive_ref_counter baseclass to use a counter only suitable for a single-threaded use. Pointers to asingle object that uses this kind of reference counter must not be used indifferent threads. The latter policy makes the reference counter thread-safe,unless the target platform doesn’t support threading. Since in modern systemssupport for threading is common, the default counter policy isthread_safe_counter.
intrusive_ref_counter is defined in<boost/smart_ptr/intrusive_ref_counter.hpp>.
namespace boost { struct thread_unsafe_counter; struct thread_safe_counter; template<class Derived, class CounterPolicy = thread_safe_counter> class intrusive_ref_counter { public: intrusive_ref_counter() noexcept; intrusive_ref_counter(const intrusive_ref_counter& v) noexcept; intrusive_ref_counter& operator=(const intrusive_ref_counter& v) noexcept; unsigned int use_count() const noexcept; protected: ~intrusive_ref_counter() = default; }; template<class Derived, class CounterPolicy> void intrusive_ptr_add_ref( const intrusive_ref_counter<Derived, CounterPolicy>* p) noexcept; template<class Derived, class CounterPolicy> void intrusive_ptr_release( const intrusive_ref_counter<Derived, CounterPolicy>* p) noexcept;}intrusive_ref_counter() noexcept;intrusive_ref_counter(const intrusive_ref_counter&) noexcept;use_count() == 0.
Note | The pointer to the constructed object is expected to be passed tointrusive_ptr constructor, assignment operator orreset method, whichwould increment the reference counter. |
~intrusive_ref_counter();Destroys the counter object.
Note | The destructor is protected so that the object can only be destroyedthrough theDerived class. |
intrusive_ref_counter& operator=(const intrusive_ref_counter& v) noexcept;Does nothing, reference counter is not modified.
unsigned int use_count() const noexcept;The current value of the reference counter.
Note | The returned value may not be actual in multi-threaded applications. |
template<class Derived, class CounterPolicy> void intrusive_ptr_add_ref( const intrusive_ref_counter<Derived, CounterPolicy>* p) noexcept;Increments the reference counter.
template<class Derived, class CounterPolicy> void intrusive_ptr_release( const intrusive_ref_counter<Derived, CounterPolicy>* p) noexcept;Decrements the reference counter. If the reference counter reaches0, callsdelete static_cast<const Derived*>(p).
local_shared_ptr is nearly identical toshared_ptr, with the only difference of note being that its reference count isupdated with non-atomic operations. As such, alocal_shared_ptr and all its copies must reside in (be local to) a singlethread (hence the name.)
local_shared_ptr can be converted toshared_ptr and vice versa. Creating alocal_shared_ptr from ashared_ptr createsa new local reference count; this means that twolocal_shared_ptr instances, both created from the sameshared_ptr, referto the same object but don’t share the same count, and as such, can safely be used by two different threads.
shared_ptr<X> p1( new X );local_shared_ptr<X> p2( p1 ); // p2.local_use_count() == 1local_shared_ptr<X> p3( p1 ); // p3.local_use_count() also 1Creating the secondlocal_shared_ptr from the first one, however, does lead to the two sharing the same count:
shared_ptr<X> p1( new X );local_shared_ptr<X> p2( p1 ); // p2.local_use_count() == 1local_shared_ptr<X> p3( p2 ); // p3.local_use_count() == 2Twoshared_ptr instances created from the samelocal_shared_ptr do share ownership:
local_shared_ptr<X> p1( new X );shared_ptr<X> p2( p1 ); // p2.use_count() == 2shared_ptr<X> p3( p1 ); // p3.use_count() == 3Herep2.use_count() is 2, becausep1 holds a reference, too.
One can think oflocal_shared_ptr<T> asshared_ptr<shared_ptr<T>>, with the outershared_ptr using non-atomic operations forits count. Converting fromlocal_shared_ptr toshared_ptr gives you a copy of the innershared_ptr; converting fromshared_ptrwraps it into an outershared_ptr with a non-atomic use count (conceptually speaking) and returns the result.
local_shared_ptr is defined in<boost/smart_ptr/local_shared_ptr.hpp>.
namespace boost { template<class T> class local_shared_ptr { public: typedef /*see below*/ element_type; // constructors constexpr local_shared_ptr() noexcept; constexpr local_shared_ptr(std::nullptr_t) noexcept; template<class Y> explicit local_shared_ptr(Y * p); template<class Y, class D> local_shared_ptr(Y * p, D d); template<class D> local_shared_ptr(std::nullptr_t p, D d); template<class Y, class D, class A> local_shared_ptr(Y * p, D d, A a); template<class D, class A> local_shared_ptr(std::nullptr_t p, D d, A a); local_shared_ptr(local_shared_ptr const & r) noexcept; template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r) noexcept; local_shared_ptr(local_shared_ptr && r) noexcept; template<class Y> local_shared_ptr(local_shared_ptr<Y> && r) noexcept; template<class Y> local_shared_ptr( shared_ptr<Y> const & r ); template<class Y> local_shared_ptr( shared_ptr<Y> && r ); template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r, element_type * p) noexcept; template<class Y> local_shared_ptr(local_shared_ptr<Y> && r, element_type * p) noexcept; template<class Y, class D> local_shared_ptr(std::unique_ptr<Y, D> && r); // destructor ~local_shared_ptr() noexcept; // assignment local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> const & r) noexcept; local_shared_ptr & operator=(local_shared_ptr const && r) noexcept; template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> const && r) noexcept; template<class Y, class D> local_shared_ptr & operator=(std::unique_ptr<Y, D> && r); local_shared_ptr & operator=(std::nullptr_t) noexcept; // reset void reset() noexcept; template<class Y> void reset(Y * p); template<class Y, class D> void reset(Y * p, D d); template<class Y, class D, class A> void reset(Y * p, D d, A a); template<class Y> void reset(local_shared_ptr<Y> const & r, element_type * p) noexcept; template<class Y> void reset(local_shared_ptr<Y> && r, element_type * p) noexcept; // accessors T & operator*() const noexcept; // only valid when T is not an array type T * operator->() const noexcept; // only valid when T is not an array type // only valid when T is an array type element_type & operator[](std::ptrdiff_t i) const noexcept; element_type * get() const noexcept; long local_use_count() const noexcept; // conversions explicit operator bool() const noexcept; template<class Y> operator shared_ptr<Y>() const noexcept; template<class Y> operator weak_ptr<Y>() const noexcept; // swap void swap(local_shared_ptr & b) noexcept; // owner_before template<class Y> bool owner_before(local_shared_ptr<Y> const & rhs) const noexcept; }; // comparisons template<class T, class U> bool operator==(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept; template<class T, class U> bool operator==(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept; template<class T, class U> bool operator==(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept; template<class T, class U> bool operator!=(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept; template<class T, class U> bool operator!=(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept; template<class T, class U> bool operator!=(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept; template<class T> bool operator==(local_shared_ptr<T> const & p, std::nullptr_t) noexcept; template<class T> bool operator==(std::nullptr_t, local_shared_ptr<T> const & p) noexcept; template<class T> bool operator!=(local_shared_ptr<T> const & p, std::nullptr_t) noexcept; template<class T> bool operator!=(std::nullptr_t, local_shared_ptr<T> const & p) noexcept; template<class T, class U> bool operator<(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept; // swap template<class T> void swap(local_shared_ptr<T> & a, local_shared_ptr<T> & b) noexcept; // get_pointer template<class T> typename local_shared_ptr<T>::element_type * get_pointer(local_shared_ptr<T> const & p) noexcept; // casts template<class T, class U> local_shared_ptr<T> static_pointer_cast(local_shared_ptr<U> const & r) noexcept; template<class T, class U> local_shared_ptr<T> const_pointer_cast(local_shared_ptr<U> const & r) noexcept; template<class T, class U> local_shared_ptr<T> dynamic_pointer_cast(local_shared_ptr<U> const & r) noexcept; template<class T, class U> local_shared_ptr<T> reinterpret_pointer_cast(local_shared_ptr<U> const & r) noexcept; // stream I/O template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, local_shared_ptr<Y> const & p); // get_deleter template<class D, class T> D * get_deleter(local_shared_ptr<T> const & p) noexcept;}typedef ... element_type;element_type isT whenT is not an array type, andU whenT isU[] orU[N].
constexpr local_shared_ptr() noexcept;constexpr local_shared_ptr(std::nullptr_t) noexcept;Constructs an emptylocal_shared_ptr.
local_use_count() == 0 && get() == 0.
template<class Y> explicit local_shared_ptr(Y * p);Constructs alocal_shared_ptr that ownsshared_ptr<T>( p ).
local_use_count() == 1 && get() == p.
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
template<class Y, class D> local_shared_ptr(Y * p, D d);template<class D> local_shared_ptr(std::nullptr_t p, D d);Constructs alocal_shared_ptr that ownsshared_ptr<T>( p, d ).
local_use_count() == 1 && get() == p.
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
template<class Y, class D, class A> local_shared_ptr(Y * p, D d, A a);template<class D, class A> local_shared_ptr(std::nullptr_t p, D d, A a);Constructs alocal_shared_ptr that ownsshared_ptr<T>( p, d, a ).
local_use_count() == 1 && get() == p.
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
local_shared_ptr(local_shared_ptr const & r) noexcept;template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r) noexcept;Y* should be convertible toT*.
Ifr is empty, constructs an emptylocal_shared_ptr; otherwise, constructs alocal_shared_ptr that shares ownership withr.
get() == r.get() && local_use_count() == r.local_use_count().
local_shared_ptr(local_shared_ptr && r) noexcept;template<class Y> local_shared_ptr(local_shared_ptr<Y> && r) noexcept;Y* should be convertible toT*.
Move-constructs alocal_shared_ptr fromr.
*this contains the old value ofr.r is empty andr.get() == 0.
template<class Y> local_shared_ptr( shared_ptr<Y> const & r );template<class Y> local_shared_ptr( shared_ptr<Y> && r );Constructs alocal_shared_ptr that ownsr.
local_use_count() == 1.get() returns the old value ofr.get().
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r, element_type * p) noexcept;constructs alocal_shared_ptr that shares ownership withr and storesp.
get() == p && local_use_count() == r.local_use_count().
template<class Y> local_shared_ptr(local_shared_ptr<Y> && r, element_type * p) noexcept;Move-constructs alocal_shared_ptr fromr, while storingp instead.
get() == p andlocal_use_count() equals the old count ofr.r is empty andr.get() == 0.
template<class Y, class D> local_shared_ptr(std::unique_ptr<Y, D> && r);Y* should be convertible toT*.
Whenr.get() == 0, equivalent tolocal_shared_ptr();
Otherwise, constructs alocal_shared_ptr that ownsshared_ptr<T>( std::move(r) ).
std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
If an exception is thrown, the constructor has no effect.
~local_shared_ptr() noexcept;If*this is empty, or shares ownership with anotherlocal_shared_ptr instance (local_use_count() > 1), there are no side effects.
Otherwise, destroys the ownedshared_ptr.
local_shared_ptr & operator=(local_shared_ptr const & r) noexcept;template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> const & r) noexcept;Equivalent tolocal_shared_ptr(r).swap(*this).
*this.
local_shared_ptr & operator=(local_shared_ptr && r) noexcept;template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> && r) noexcept;template<class Y, class D> local_shared_ptr & operator=(std::unique_ptr<Y, D> && r);Equivalent tolocal_shared_ptr(std::move(r)).swap(*this).
*this.
local_shared_ptr & operator=(std::nullptr_t) noexcept;Equivalent tolocal_shared_ptr().swap(*this).
*this.
void reset() noexcept;Equivalent tolocal_shared_ptr().swap(*this).
template<class Y> void reset(Y * p);Equivalent tolocal_shared_ptr(p).swap(*this).
template<class Y, class D> void reset(Y * p, D d);Equivalent tolocal_shared_ptr(p, d).swap(*this).
template<class Y, class D, class A> void reset(Y * p, D d, A a);Equivalent tolocal_shared_ptr(p, d, a).swap(*this).
template<class Y> void reset(local_shared_ptr<Y> const & r, element_type * p) noexcept;Equivalent tolocal_shared_ptr(r, p).swap(*this).
template<class Y> void reset(local_shared_ptr<Y> && r, element_type * p) noexcept;Equivalent tolocal_shared_ptr(std::move(r), p).swap(*this).
T & operator*() const noexcept;T should not be an array type.
*get().
T * operator->() const noexcept;T should not be an array type.
get().
element_type & operator[](std::ptrdiff_t i) const noexcept;T should be an array type. The stored pointer must not be 0.i >= 0. IfT isU[N],i < N.
get()[i].
element_type * get() const noexcept;The stored pointer.
long local_use_count() const noexcept;The number oflocal_shared_ptr objects,*this included, that share ownership with*this, or 0 when*this is empty.
explicit operator bool() const noexcept;get() != 0.
Note | On C++03 compilers, the return value is of an unspecified type. |
template<class Y> operator shared_ptr<Y>() const noexcept;template<class Y> operator weak_ptr<Y>() const noexcept;T* should be convertible toY*.
a copy of the ownedshared_ptr.
void swap(local_shared_ptr & b) noexcept;Exchanges the contents of the two smart pointers.
template<class Y> bool owner_before(local_shared_ptr<Y> const & rhs) const noexcept;See the description ofoperator<.
template<class T, class U> bool operator==(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;template<class T, class U> bool operator==(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;template<class T, class U> bool operator==(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;a.get() == b.get().
template<class T, class U> bool operator!=(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;template<class T, class U> bool operator!=(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;template<class T, class U> bool operator!=(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;a.get() != b.get().
template<class T> bool operator==(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;template<class T> bool operator==(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;p.get() == 0.
template<class T> bool operator!=(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;template<class T> bool operator!=(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;p.get() != 0.
template<class T, class U> bool operator<(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;An unspecified value such that
operator< is a strict weak ordering as described in section [lib.alg.sorting] of the C++ standard;
under the equivalence relation defined byoperator<,!(a < b) && !(b < a), twolocal_shared_ptr instancesare equivalent if and only if they share ownership or are both empty.
Note | Allowslocal_shared_ptr objects to be used as keys in associative containers. |
Note | The rest of the comparison operators are omitted by design. |
template<class T> void swap(local_shared_ptr<T> & a, local_shared_ptr<T> & b) noexcept;Equivalent toa.swap(b).
template<class T> typename local_shared_ptr<T>::element_type * get_pointer(local_shared_ptr<T> const & p) noexcept;p.get().
Note | Provided as an aid to generic programming. Used bymem_fn. |
template<class T, class U> local_shared_ptr<T> static_pointer_cast(local_shared_ptr<U> const & r) noexcept;The expressionstatic_cast<T*>( (U*)0 ) must be well-formed.
local_shared_ptr<T>( r, static_cast<typename local_shared_ptr<T>::element_type*>(r.get()) ).
Caution | The seemingly equivalent expressionlocal_shared_ptr<T>(static_cast<T*>(r.get())) will eventuallyresult in undefined behavior, attempting to delete the same object twice. |
template<class T, class U> local_shared_ptr<T> const_pointer_cast(local_shared_ptr<U> const & r) noexcept;The expressionconst_cast<T*>( (U*)0 ) must be well-formed.
local_shared_ptr<T>( r, const_cast<typename local_shared_ptr<T>::element_type*>(r.get()) ).
template<class T, class U> local_shared_ptr<T> dynamic_pointer_cast(local_shared_ptr<U> const & r) noexcept;The expressiondynamic_cast<T*>( (U*)0 ) must be well-formed.
Whendynamic_cast<typename local_shared_ptr<T>::element_type*>(r.get()) returns a nonzero valuep,local_shared_ptr<T>(r, p);
Otherwise,local_shared_ptr<T>().
template<class T, class U> local_shared_ptr<T> reinterpret_pointer_cast(local_shared_ptr<U> const & r) noexcept;The expressionreinterpret_cast<T*>( (U*)0 ) must be well-formed.
local_shared_ptr<T>( r, reinterpret_cast<typename local_shared_ptr<T>::element_type*>(r.get()) ).
template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, local_shared_ptr<Y> const & p);os << p.get();.
os.
template<class D, class T> D * get_deleter(local_shared_ptr<T> const & p) noexcept;If*this owns ashared_ptr instancep,get_deleter<D>( p ), otherwise 0.
The function templatesmake_local_shared andallocate_local_shared provideconvenient, safe and efficient ways to createlocal_shared_ptr objects. Theyare analogous tomake_shared andallocate_shared forshared_ptr.
make_local_shared andallocate_local_shared are defined in<boost/smart_ptr/make_local_shared.hpp>.
namespace boost {// only if T is not an array type template<class T, class... Args> local_shared_ptr<T> make_local_shared(Args&&... args); template<class T, class A, class... Args> local_shared_ptr<T> allocate_local_shared(const A& a, Args&&... args);// only if T is an array type of the form U[] template<class T> local_shared_ptr<T> make_local_shared(std::size_t n); template<class T, class A> local_shared_ptr<T> allocate_local_shared(const A& a, std::size_t n);// only if T is an array type of the form U[N] template<class T> local_shared_ptr<T> make_local_shared(); template<class T, class A> local_shared_ptr<T> allocate_local_shared(const A& a);// only if T is an array type of the form U[] template<class T> local_shared_ptr<T> make_local_shared(std::size_t n, const remove_extent_t<T>& v); template<class T, class A> local_shared_ptr<T> allocate_local_shared(const A& a, std::size_t n, const remove_extent_t<T>& v);// only if T is an array type of the form U[N] template<class T> local_shared_ptr<T> make_local_shared(const remove_extent_t<T>& v); template<class T, class A> local_shared_ptr<T> allocate_local_shared(const A& a, const remove_extent_t<T>& v);// only if T is not an array type of the form U[] template<class T> local_shared_ptr<T> make_local_shared_noinit(); template<class T, class A> local_shared_ptr<T> allocate_local_shared_noinit(const A& a);// only if T is an array type of the form U[N] template<class T> local_shared_ptr<T> make_local_shared_noinit(std::size_t n); template<class T, class A> local_shared_ptr<T> allocate_local_shared_noinit(const A& a, std::size_t n);}The requirements and effects of these functions are the same asmake_sharedandallocate_shared, except that alocal_shared_ptr is returned.
The pointer cast function templates (static_pointer_cast,dynamic_pointer_cast,const_pointer_cast, andreinterpret_pointer_cast)provide a way to write generic pointer castings for raw pointers,std::shared_ptr andstd::unique_ptr.
There is test and example code inpointer_cast_test.cpp
Boost smart pointers usually overload those functions to provide a mechanismto emulate pointers casts. For example,shared_ptr<T> implements a staticpointer cast this way:
template<class T, class U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& p);Pointer cast functions templates are overloads ofstatic_pointer_cast,dynamic_pointer_cast,const_pointer_cast, andreinterpret_pointer_castfor raw pointers,std::shared_ptr andstd::unique_ptr. This way whendeveloping pointer type independent classes, for example, memory managers orshared memory compatible classes, the same code can be used for raw and smartpointers.
The generic pointer casts are defined in<boost/pointer_cast.hpp>.
namespace boost { template<class T, class U> T* static_pointer_cast(U* p) noexcept; template<class T, class U> T* dynamic_pointer_cast(U* p) noexcept; template<class T, class U> T* const_pointer_cast(U* p) noexcept; template<class T, class U> T* reinterpret_pointer_cast(U* p) noexcept; template<class T, class U> std::shared_ptr<T> static_pointer_cast(const std::shared_ptr<U>& p) noexcept; template<class T, class U> std::shared_ptr<T> dynamic_pointer_cast(const std::shared_ptr<U>& p) noexcept; template<class T, class U> std::shared_ptr<T> const_pointer_cast(const std::shared_ptr<U>& p) noexcept; template<class T, class U> std::shared_ptr<T> reinterpret_pointer_cast(const std::shared_ptr<U>& p) noexcept; template<class T, class U> std::unique_ptr<T> static_pointer_cast(std::unique_ptr<U>&& p) noexcept; template<class T, class U> std::unique_ptr<T> dynamic_pointer_cast(std::unique_ptr<U>&& p) noexcept; template<class T, class U> std::unique_ptr<T> const_pointer_cast(std::unique_ptr<U>&& p) noexcept; template<class T, class U> std::unique_ptr<T> reinterpret_pointer_cast(std::unique_ptr<U>&& p) noexcept;}template<class T, class U> T* static_pointer_cast(U* p) noexcept;static_cast<T*>(p)
template<class T, class U> std::shared_ptr<T> static_pointer_cast(const std::shared_ptr<U>& p) noexcept;std::static_pointer_cast<T>(p)
template<class T, class U> std::unique_ptr<T> static_pointer_cast(std::unique_ptr<U>&& p) noexcept;The expressionstatic_cast<T*>((U*)0) must be well-formed.
std::unique_ptr<T>(static_cast<typenamestd::unique_ptr<T>::element_type*>(p.release())).
Caution | The seemingly equivalent expressionstd::unique_ptr<T>(static_cast<T*>(p.get())) will eventually result inundefined behavior, attempting to delete the same object twice. |
template<class T, class U> T* dynamic_pointer_cast(U* p) noexcept;dynamic_cast<T*>(p)
template<class T, class U> std::shared_ptr<T> dynamic_pointer_cast(const std::shared_ptr<U>& p) noexcept;std::dynamic_pointer_cast<T>(p)
template<class T, class U> std::unique_ptr<T> dynamic_pointer_cast(std::unique_ptr<U>&& p) noexcept;The expressionstatic_cast<T*>((U*)0) must be well-formed.
T must have a virtual destructor.
Whendynamic_cast<typename std::unique_ptr<T>::element_type*>(p.get())returns a non-zero value,std::unique_ptr<T>(dynamic_cast<typenamestd::unique_ptr<T>::element_type*>(p.release()));.
Otherwise,std::unique_ptr<T>().
template<class T, class U> T* const_pointer_cast(U* p) noexcept;const_cast<T*>(p)
template<class T, class U> std::shared_ptr<T> const_pointer_cast(const std::shared_ptr<U>& p) noexcept;std::const_pointer_cast<T>(p)
template<class T, class U> std::unique_ptr<T> const_pointer_cast(std::unique_ptr<U>&& p) noexcept;The expressionconst_cast<T*>((U*)0) must be well-formed.
std::unique_ptr<T>(const_cast<typenamestd::unique_ptr<T>::element_type*>(p.release())).
template<class T, class U> T* reinterpret_pointer_cast(U* p) noexcept;reinterpret_cast<T*>(p)
template<class T, class U> std::shared_ptr<T> reinterpret_pointer_cast(const std::shared_ptr<U>& p) noexcept;std::reinterpret_pointer_cast<T>(p)
template<class T, class U> std::unique_ptr<T> reinterpret_pointer_cast(std::unique_ptr<U>&& p) noexcept;The expressionreinterpret_cast<T*>((U*)0) must be well-formed.
std::unique_ptr<T>(reinterpret_cast<typenamestd::unique_ptr<T>::element_type*>(p.release())).
The following example demonstrates how the generic pointer casts help uscreate pointer independent code.
#include <boost/pointer_cast.hpp>#include <boost/shared_ptr.hpp>class base {public: virtual ~base() { }};class derived : public base { };template<class Ptr>void check_if_it_is_derived(const Ptr& ptr){ assert(boost::dynamic_pointer_cast<derived>(ptr) != 0);}int main(){ base* ptr = new derived; boost::shared_ptr<base> sptr(new derived); check_if_it_is_derived(ptr); check_if_it_is_derived(sptr); delete ptr;}Thepointer_to_other utility provides a way, given a source pointer type, to obtain a pointer of the same typeto another pointee type.
There is test/example code inpointer_to_other_test.cpp.
When building pointer independent classes, like memory managers, allocators, or containers, there is often a need todefine pointers generically, so that if a template parameter represents a pointer (for example, a raw or smart pointerto anint), we can define another pointer of the same type to another pointee (a raw or smart pointer to afloat.)
template <class IntPtr> class FloatPointerHolder{ // Let's define a pointer to a float typedef typename boost::pointer_to_other <IntPtr, float>::type float_ptr_t; float_ptr_t float_ptr;};pointer_to_other is defined in<boost/smart_ptr/pointer_to_other.hpp>.
namespace boost { template<class T, class U> struct pointer_to_other; template<class T, class U, template <class> class Sp> struct pointer_to_other< Sp<T>, U > { typedef Sp<U> type; }; template<class T, class T2, class U, template <class, class> class Sp> struct pointer_to_other< Sp<T, T2>, U > { typedef Sp<U, T2> type; }; template<class T, class T2, class T3, class U, template <class, class, class> class Sp> struct pointer_to_other< Sp<T, T2, T3>, U > { typedef Sp<U, T2, T3> type; }; template<class T, class U> struct pointer_to_other< T*, U > { typedef U* type; };}If these definitions are not correct for a specific smart pointer, we can define a specialization ofpointer_to_other.
// Let's define a memory allocator that can// work with raw and smart pointers#include <boost/pointer_to_other.hpp>template <class VoidPtr>class memory_allocator{ // Predefine a memory_block struct block; // Define a pointer to a memory_block from a void pointer // If VoidPtr is void *, block_ptr_t is block* // If VoidPtr is smart_ptr<void>, block_ptr_t is smart_ptr<block> typedef typename boost::pointer_to_other <VoidPtr, block>::type block_ptr_t; struct block { std::size_t size; block_ptr_t next_block; }; block_ptr_t free_blocks;};As we can see, usingpointer_to_other we can create pointer independent code.
The class templateatomic_shared_ptr<T> implements the interface ofstd::atomicfor a contained value of typeshared_ptr<T>. Concurrent access toatomic_shared_ptris not a data race.
atomic_shared_ptr is defined in<boost/smart_ptr/atomic_shared_ptr.hpp>.
namespace boost { template<class T> class atomic_shared_ptr { private: shared_ptr<T> p_; // exposition only atomic_shared_ptr(const atomic_shared_ptr&) = delete; atomic_shared_ptr& operator=(const atomic_shared_ptr&) = delete; public: constexpr atomic_shared_ptr() noexcept; atomic_shared_ptr( shared_ptr<T> p ) noexcept; atomic_shared_ptr& operator=( shared_ptr<T> r ) noexcept; bool is_lock_free() const noexcept; shared_ptr<T> load( int = 0 ) const noexcept; operator shared_ptr<T>() const noexcept; void store( shared_ptr<T> r, int = 0 ) noexcept; shared_ptr<T> exchange( shared_ptr<T> r, int = 0 ) noexcept; bool compare_exchange_weak( shared_ptr<T>& v, const shared_ptr<T>& w, int, int ) noexcept; bool compare_exchange_weak( shared_ptr<T>& v, const shared_ptr<T>& w, int = 0 ) noexcept; bool compare_exchange_strong( shared_ptr<T>& v, const shared_ptr<T>& w, int, int ) noexcept; bool compare_exchange_strong( shared_ptr<T>& v, const shared_ptr<T>& w, int = 0 ) noexcept; bool compare_exchange_weak( shared_ptr<T>& v, shared_ptr<T>&& w, int, int ) noexcept; bool compare_exchange_weak( shared_ptr<T>& v, shared_ptr<T>&& w, int = 0 ) noexcept; bool compare_exchange_strong( shared_ptr<T>& v, shared_ptr<T>&& w, int, int ) noexcept; bool compare_exchange_strong( shared_ptr<T>& v, shared_ptr<T>&& w, int = 0 ) noexcept; };}constexpr atomic_shared_ptr() noexcept;Default-initializesp_.
atomic_shared_ptr( shared_ptr<T> p ) noexcept;Initializesp_ top.
atomic_shared_ptr& operator=( shared_ptr<T> r ) noexcept;p_.swap(r).
*this.
bool is_lock_free() const noexcept;false.
Note | This implementation is not lock-free. |
shared_ptr<T> load( int = 0 ) const noexcept;operator shared_ptr<T>() const noexcept;p_.
Note | Theint argument is intended to be of typememory_order, but is ignored. This implementation is lock-based and therefore always sequentially consistent. |
void store( shared_ptr<T> r, int = 0 ) noexcept;p_.swap(r).
shared_ptr<T> exchange( shared_ptr<T> r, int = 0 ) noexcept;p_.swap(r).
The old value ofp_.
bool compare_exchange_weak( shared_ptr<T>& v, const shared_ptr<T>& w, int, int ) noexcept;bool compare_exchange_weak( shared_ptr<T>& v, const shared_ptr<T>& w, int = 0 ) noexcept;bool compare_exchange_strong( shared_ptr<T>& v, const shared_ptr<T>& w, int, int ) noexcept;bool compare_exchange_strong( shared_ptr<T>& v, const shared_ptr<T>& w, int = 0 ) noexcept;Ifp_ is equivalent tov, assignsw top_, otherwise assignsp_ tov.
true ifp_ was equivalent tov,false otherwise.
Twoshared_ptr instances are equivalent if they store the same pointer value andshare ownership.
bool compare_exchange_weak( shared_ptr<T>& v, shared_ptr<T>&& w, int, int ) noexcept;bool compare_exchange_weak( shared_ptr<T>& v, shared_ptr<T>&& w, int = 0 ) noexcept;bool compare_exchange_strong( shared_ptr<T>& v, shared_ptr<T>&& w, int, int ) noexcept;bool compare_exchange_strong( shared_ptr<T>& v, shared_ptr<T>&& w, int = 0 ) noexcept;Ifp_ is equivalent tov, assignsstd::move(w) top_, otherwise assignsp_ tov.
true ifp_ was equivalent tov,false otherwise.
The old value ofw is not preserved in either case.
A proven technique (that works in C, too) for separating interface from implementation is to use a pointer to an incomplete class as an opaque handle:
class FILE;FILE * fopen(char const * name, char const * mode);void fread(FILE * f, void * data, size_t size);void fclose(FILE * f);It is possible to express the above interface usingshared_ptr, eliminating the need to manually callfclose:
class FILE;shared_ptr<FILE> fopen(char const * name, char const * mode);void fread(shared_ptr<FILE> f, void * data, size_t size);This technique relies onshared_ptr’s ability to execute a custom deleter, eliminating the explicit call tofclose, and on the fact thatshared_ptr<X> can be copied and destroyed whenX is incomplete.
A C++ specific variation of the incomplete class pattern is the "Pimpl" idiom. The incomplete class is not exposed to the user; it is hidden behind a forwarding facade.shared_ptr can be used to implement a "Pimpl":
// file.hpp:class file{private: class impl; shared_ptr<impl> pimpl_;public: file(char const * name, char const * mode); // compiler generated members are fine and useful void read(void * data, size_t size);};// file.cpp:#include "file.hpp"class file::impl{private: impl(impl const &); impl & operator=(impl const &); // private datapublic: impl(char const * name, char const * mode) { ... } ~impl() { ... } void read(void * data, size_t size) { ... }};file::file(char const * name, char const * mode): pimpl_(new impl(name, mode)){}void file::read(void * data, size_t size){ pimpl_->read(data, size);}The key thing to note here is that the compiler-generated copy constructor, assignment operator, and destructor all have a sensible meaning. As a result,file isCopyConstructible andAssignable, allowing its use in standard containers.
Another widely used C++ idiom for separating inteface and implementation is to use abstract base classes and factory functions.The abstract classes are sometimes called "interfaces" and the pattern is known as "interface-based programming". Again,shared_ptr can be used as the return type of the factory functions:
// X.hpp:class X{public: virtual void f() = 0; virtual void g() = 0;protected: ~X() {}};shared_ptr<X> createX();// X.cpp:class X_impl: public X{private: X_impl(X_impl const &); X_impl & operator=(X_impl const &);public: virtual void f() { // ... } virtual void g() { // ... }};shared_ptr<X> createX(){ shared_ptr<X> px(new X_impl); return px;}A key property ofshared_ptr is that the allocation, construction, deallocation, and destruction details are captured at the point of construction, inside the factory function.
Note the protected and nonvirtual destructor in the example above. The client code cannot, and does not need to, delete a pointer toX; theshared_ptr<X> instance returned fromcreateX will correctly call~X_impl.
delete px.get()It is often desirable to prevent client code from deleting a pointer that is being managed byshared_ptr. The previous technique showed one possible approach, using a protected destructor. Another alternative is to use a private deleter:
class X{private: ~X(); class deleter; friend class deleter; class deleter { public: void operator()(X * p) { delete p; } };public: static shared_ptr<X> create() { shared_ptr<X> px(new X, X::deleter()); return px; }};shared_ptr can be used in creating C++ wrappers over existing C style library interfaces that return raw pointers from their factory functionsto encapsulate allocation details. As an example, consider this interface, whereCreateX might allocateX from its own private heap,~X maybe inaccessible, orX may be incomplete:
X * CreateX();void DestroyX(X *);
The only way to reliably destroy a pointer returned byCreateX is to callDestroyX.
Here is how ashared_ptr-based wrapper may look like:
shared_ptr<X> createX(){ shared_ptr<X> px(CreateX(), DestroyX); return px;}Client code that callscreateX still does not need to know how the object has been allocated, but now the destruction is automatic.
Sometimes it is desirable to create ashared_ptr to an already existing object, so that theshared_ptr does not attempt to destroy theobject when there are no more references left. As an example, the factory function:
shared_ptr<X> createX();
in certain situations may need to return a pointer to a statically allocatedX instance.
The solution is to use a custom deleter that does nothing:
struct null_deleter{ void operator()(void const *) const { }};static X x;shared_ptr<X> createX(){ shared_ptr<X> px(&x, null_deleter()); return px;}The same technique works for any object known to outlive the pointer.
Background: COM objects have an embedded reference count and two member functions that manipulate it.AddRef() increments the count.Release() decrements the count and destroys itself when the count drops to zero.
It is possible to hold a pointer to a COM object in ashared_ptr:
shared_ptr<IWhatever> make_shared_from_COM(IWhatever * p){ p->AddRef(); shared_ptr<IWhatever> pw(p, mem_fn(&IWhatever::Release)); return pw;}Note, however, thatshared_ptr copies created frompw will not "register" in the embedded count of the COM object;they will share the single reference created inmake_shared_from_COM. Weak pointers created frompw will be invalidated when the lastshared_ptr is destroyed, regardless of whether the COM object itself is still alive.
Asexplained in themem_fn documentation, you need to#define BOOST_MEM_FN_ENABLE_STDCALL first.
This is a generalization of the above technique. The example assumes that the object implements the two functions required byintrusive_ptr,intrusive_ptr_add_ref andintrusive_ptr_release:
template<class T> struct intrusive_deleter{ void operator()(T * p) { if(p) intrusive_ptr_release(p); }};shared_ptr<X> make_shared_from_intrusive(X * p){ if(p) intrusive_ptr_add_ref(p); shared_ptr<X> px(p, intrusive_deleter<X>()); return px;}One of the design goals ofshared_ptr is to be used in library interfaces. It is possible to encounter a situation where a library takes ashared_ptr argument, but the object at hand is being managed by a different reference counted or linked smart pointer.
It is possible to exploitshared_ptr’s custom deleter feature to wrap this existing smart pointer behind ashared_ptr facade:
template<class P> struct smart_pointer_deleter{private: P p_;public: smart_pointer_deleter(P const & p): p_(p) { } void operator()(void const *) { p_.reset(); } P const & get() const { return p_; }};shared_ptr<X> make_shared_from_another(another_ptr<X> qx){ shared_ptr<X> px(qx.get(), smart_pointer_deleter< another_ptr<X> >(qx)); return px;}One subtle point is that deleters are not allowed to throw exceptions, and the above example as written assumes thatp_.reset() doesn’t throw.If this is not the case,p_.reset(); should be wrapped in atry {} catch(…) {} block that ignores exceptions. In the (usually unlikely) eventwhen an exception is thrown and ignored,p_ will be released when the lifetime of the deleter ends. This happens when all references, includingweak pointers, are destroyed or reset.
Another twist is that it is possible, given the aboveshared_ptr instance, to recover the original smart pointer, usingget_deleter:
void extract_another_from_shared(shared_ptr<X> px){ typedef smart_pointer_deleter< another_ptr<X> > deleter; if(deleter const * pd = get_deleter<deleter>(px)) { another_ptr<X> qx = pd->get(); } else { // not one of ours }}Sometimes it is necessary to obtain ashared_ptr given a raw pointer to an object that is already managed by anothershared_ptr instance. Example:
void f(X * p){ shared_ptr<X> px(???);}Insidef, we’d like to create ashared_ptr to*p.
In the general case, this problem has no solution. One approach is to modifyf to take ashared_ptr, if possible:
void f(shared_ptr<X> px);
The same transformation can be used for nonvirtual member functions, to convert the implicitthis:
void X::f(int m);
would become a free function with ashared_ptr first argument:
void f(shared_ptr<X> this_, int m);
Iff cannot be changed, butX uses intrusive counting, usemake_shared_from_intrusive described above. Or, if it’s known that theshared_ptr created inf will never outlive the object, usea null deleter.
Some designs require objects to register themselves on construction with a central authority. When the registration routines take ashared_ptr, this leads to the question how could a constructor obtain ashared_ptr tothis:
class X{public: X() { shared_ptr<X> this_(???); }};In the general case, the problem cannot be solved. TheX instance being constructed can be an automatic variable or a static variable; it can be created on the heap:
shared_ptr<X> px(new X);
but at construction time,px does not exist yet, and it is impossible to create anothershared_ptr instance that shares ownership with it.
Depending on context, if the innershared_ptr this_ doesn’t need to keep the object alive, use anull_deleter as explainedhere andhere.IfX is supposed to always live on the heap, and be managed by ashared_ptr, use a static factory function:
class X{private: X() { ... }public: static shared_ptr<X> create() { shared_ptr<X> px(new X); // use px as 'this_' return px; }};Sometimes it is needed to obtain ashared_ptr fromthis in a virtual member function under the assumption thatthis is already managed by ashared_ptr.The transformationsdescribed in the previous technique cannot be applied.
A typical example:
class X{public: virtual void f() = 0;protected: ~X() {}};class Y{public: virtual shared_ptr<X> getX() = 0;protected: ~Y() {}};// --class impl: public X, public Y{public: impl() { ... } virtual void f() { ... } virtual shared_ptr<X> getX() { shared_ptr<X> px(???); return px; }};The solution is to keep a weak pointer tothis as a member inimpl:
class impl: public X, public Y{private: weak_ptr<impl> weak_this; impl(impl const &); impl & operator=(impl const &); impl() { ... }public: static shared_ptr<impl> create() { shared_ptr<impl> pi(new impl); pi->weak_this = pi; return pi; } virtual void f() { ... } virtual shared_ptr<X> getX() { shared_ptr<X> px(weak_this); return px; }};The library now includes a helper class templateenable_shared_from_this that can be used to encapsulate the solution:
class impl: public X, public Y, public enable_shared_from_this<impl>{public: impl(impl const &); impl & operator=(impl const &);public: virtual void f() { ... } virtual shared_ptr<X> getX() { return shared_from_this(); }}Note that you no longer need to manually initialize theweak_ptr member inenable_shared_from_this. Constructing ashared_ptr toimpl takes care of that.
Some library interfaces use opaque handles, a variation of theincomplete class technique described above. An example:
typedef void * HANDLE;HANDLE CreateProcess();void CloseHandle(HANDLE);Instead of a raw pointer, it is possible to useshared_ptr as the handle and get reference counting and automatic resource management for free:
typedef shared_ptr<void> handle;handle createProcess(){ shared_ptr<void> pv(CreateProcess(), CloseHandle); return pv;}shared_ptr<void> can automatically execute cleanup code when control leaves a scope.
Executingf(p), wherep is a pointer:
shared_ptr<void> guard(p, f);Executing arbitrary code:f(x, y):
shared_ptr<void> guard(static_cast<void*>(0), bind(f, x, y));shared_ptr<void> can act as a generic object pointer similar tovoid*. When ashared_ptr<void> instance constructed as:
shared_ptr<void> pv(new X);
is destroyed, it will correctly dispose of theX object by executing~X.
This propery can be used in much the same manner as a rawvoid* is used to temporarily strip type information from an object pointer.Ashared_ptr<void> can later be cast back to the correct type by usingstatic_pointer_cast.
shared_ptr instancesshared_ptr andweak_ptr supportoperator< comparisons required by standard associative containers such asstd::map. This can beused to non-intrusively associate arbitrary data with objects managed byshared_ptr:
typedef int Data;std::map<shared_ptr<void>, Data> userData;// or std::map<weak_ptr<void>, Data> userData; to not affect the lifetimeshared_ptr<X> px(new X);shared_ptr<int> pi(new int(3));userData[px] = 42;userData[pi] = 91;shared_ptr as aCopyConstructible mutex lockSometimes it’s necessary to return a mutex lock from a function, and a noncopyable lock cannot be returned by value. It is possible to useshared_ptr as a mutex lock:
class mutex{public: void lock(); void unlock();};shared_ptr<mutex> lock(mutex & m){ m.lock(); return shared_ptr<mutex>(&m, mem_fn(&mutex::unlock));}Better yet, theshared_ptr instance acting as a lock can be encapsulated in a dedicatedshared_lock class:
class shared_lock{private: shared_ptr<void> pv;public: template<class Mutex> explicit shared_lock(Mutex & m): pv((m.lock(), &m), mem_fn(&Mutex::unlock)) {}};shared_lock can now be used as:
shared_lock lock(m);
Note thatshared_lock is not templated on the mutex type, thanks toshared_ptr<void>’s ability to hide type information.
shared_ptr implements the ownership semantics required from theWrap/CallProxy scheme described in Bjarne Stroustrup’s article"Wrapping C++ Member Function Calls" (available online athttp://www.stroustrup.com/wrapper.pdf). An implementation is given below:
template<class T> class pointer{private: T * p_;public: explicit pointer(T * p): p_(p) { } shared_ptr<T> operator->() const { p_->prefix(); return shared_ptr<T>(p_, mem_fn(&T::suffix)); }};class X{private: void prefix(); void suffix(); friend class pointer<X>;public: void f(); void g();};int main(){ X x; pointer<X> px(&x); px->f(); px->g();}In some situations, a singlepx.reset() can trigger an expensive deallocation in a performance-critical region:
class X; // ~X is expensiveclass Y{ shared_ptr<X> px;public: void f() { px.reset(); }};The solution is to postpone the potential deallocation by movingpx to a dedicated free list that can be periodically emptied when performance and response times are not an issue:
vector< shared_ptr<void> > free_list;class Y{ shared_ptr<X> px;public: void f() { free_list.push_back(px); px.reset(); }};// periodically invoke free_list.clear() when convenientAnother variation is to move the free list logic to the construction point by using a delayed deleter:
struct delayed_deleter{ template<class T> void operator()(T * p) { try { shared_ptr<void> pv(p); free_list.push_back(pv); } catch(...) { } }};Make the object hold ashared_ptr to itself, using anull_deleter:
class X{private: shared_ptr<X> this_; int i_;public: explicit X(int i): this_(this, null_deleter()), i_(i) { } // repeat in all constructors (including the copy constructor!) X(X const & rhs): this_(this, null_deleter()), i_(rhs.i_) { } // do not forget to not assign this_ in the copy assignment X & operator=(X const & rhs) { i_ = rhs.i_; } weak_ptr<X> get_weak_ptr() const { return this_; }};When the object’s lifetime ends,X::this_ will be destroyed, and all weak pointers will automatically expire.
Greg Colvinproposedto the C++ Standards Committee classes namedauto_ptr andcounted_ptr which were verysimilar to what we now callscoped_ptr andshared_ptr. In one of the very few caseswhere the Library Working Group’s recommendations were not followed by the full committee,counted_ptr was rejected and surprising transfer-of-ownership semantics were added toauto_ptr.
Beman Dawes proposed reviving the original semantics under the namessafe_ptr andcounted_ptr,meeting of Per Andersson, Matt Austern, Greg Colvin, Sean Corfield, Pete Becker, Nico Josuttis,Dietmar Kühl, Nathan Myers, Chichiang Wan and Judy Ward. During the discussion, the four new classnames were finalized, it was decided that there was no need to exactly follow thestd::auto_ptrinterface, and various function signatures and semantics were finalized.
Over the next three months, several implementations were considered forshared_ptr, and discussedon theboost.org mailing list. The implementation questions revolved aroundthe reference count which must be kept, either attached to the pointed to object, or detached elsewhere.Each of those variants have themselves two major variants:
Direct detached: theshared_ptr contains a pointer to the object, and a pointer to the count.
Indirect detached: theshared_ptr contains a pointer to a helper object, which in turn contains a pointer to the object and the count.
Embedded attached: the count is a member of the object pointed to.
Placement attached: the count is attached via operator new manipulations.
Each implementation technique has advantages and disadvantages. We went so far as to run various timingsof the direct and indirect approaches, and found that at least on Intel Pentium chips there was very littlemeasurable difference. Kevlin Henney provided a paper he wrote on "Counted Body Techniques." Dietmar Kühlsuggested an elegant partial template specialization technique to allow users to choose which implementationthey preferred, and that was also experimented with.
But Greg Colvin and Jerry Schwarz argued that "parameterization will discourage users", and in the end we chooseto supply only the direct implementation.
In April and May, 1999, Valentin Bonnard and David Abrahams made a number of suggestions resulting in numerous improvements.
Luis Coelho providedshared_ptr::swap andshared_array::swap.
Darin Adler providedoperator ==,operator !=, andstd::swap andstd::less specializations for shared types.
Vladimir Prus suggested requiring a complete type on destruction. Refinement evolved in discussions including Dave Abrahams,Greg Colvin, Beman Dawes, Rainer Deyke, Peter Dimov, John Maddock, Vladimir Prus, Shankar Sai, and others.
Peter Dimov reworked all four classes, adding features, fixing bugs, splitting them into four separate headers, and addingweak_ptr.
Peter Dimov, Beman Dawes and Greg Colvinproposedshared_ptrandweak_ptr for inclusion in the Standard Library via the first Library Technical Report (known as TR1). The proposal wasaccepted and eventually went on to become a part of the C++ standard in its 2011 iteration.
Peter Dimov and Beman Dawesproposed a number of enhancementstoshared_ptr as it was entering the working paper that eventually became the C++11 standard.
Glen Fernandes provided implementations ofmake_shared andallocate_shared for arrays. They achieve a single allocationfor an array that can be initialized with constructor arguments or initializer lists as well as overloads for default initializationand no value initialization.
Peter Dimov aided this development by extendingshared_ptr to support arrays via the syntaxshared_ptr<T[]> andshared_ptr<T[N]>.
Peter Dimovproposed the extension ofshared_ptr to supportarrays for inclusion into the standard, and it was accepted.
Glen Fernandes updatedmake_shared andallocate_shared to conform to the specification in C++ standard paperN3870, and implementedmake_unique for arrays and objects.
Peter Dimov and Glen Fernandes updated the scalar and array implementations, respectively, to resolve C++ standard library defect 2070.
Glen Fernandes rewroteallocate_shared andmake_shared for arrays for a more optimal and more maintainable implementation.
Peter Dimov and Glen Fernandes rewrote the documentation in Asciidoc format.
Peter Dimov addedatomic_shared_ptr andlocal_shared_ptr.
Note | This facility is deprecated because ashared_ptr toT[] orT[N]is now available, and is superior in every regard. |
Theshared_array class template stores a pointer to a dynamically allocatedarray. (Dynamically allocated array are allocated with the C++new[]expression.) The object pointed to is guaranteed to be deleted when the lastshared_array pointing to it is destroyed or reset.
Everyshared_array meets theCopyConstructible andAssignablerequirements of the C++ Standard Library, and so can be used in standardlibrary containers. Comparison operators are supplied so that shared_arrayworks with the standard library’s associative containers.
Normally, ashared_array cannot correctly hold a pointer to an object thathas been allocated with the non-array form ofnew. Seeshared_ptr for thatusage.
Because the implementation uses reference counting, cycles ofshared_arrayinstances will not be reclaimed. For example, ifmain holds a shared_arraytoA, which directly or indirectly holds a shared_array back toA, the usecount ofA will be 2. Destruction of the originalshared_array will leaveA dangling with a use count of 1.
Ashared_ptr to astd::vector is an alternative to ashared_array thatis a bit heavier duty but far more flexible.
The class template is parameterized onT, the type of the object pointed to.shared_array and most of its member functions place no requirements onT;it is allowed to be an incomplete type, orvoid. Member functions that doplace additional requirements (constructors, reset) are explicitly documentedbelow.
namespace boost { template<class T> class shared_array { public: typedef T element_type; explicit shared_array(T* p = 0); template<class D> shared_array(T* p, D d); shared_array(const shared_array& v) noexcept; ~shared_array() noexcept; shared_array& operator=(const shared_array& v) noexcept; void reset(T* p = 0); template<class D> void reset(T* p, D d); T& operator[](std::ptrdiff_t n) const noexcept; T* get() const noexcept; bool unique() const noexcept; long use_count() const noexcept; explicit operator bool() const noexcept; void swap(shared_array<T>& v) noexcept; }; template<class T> bool operator==(const shared_array<T>& a, const shared_array<T>& b) noexcept; template<class T> bool operator!=(const shared_array<T>& a, const shared_array<T>& b) noexcept; template<class T> bool operator<(const shared_array<T>& a, const shared_array<T>& b) noexcept; template<class T> void swap(shared_array<T>& a, shared_array<T>& b) noexcept;}typedef T element_type;Provides the type of the stored pointer.
explicit shared_array(T* p = 0);Constructs ashared_array, storing a copy ofp, which must be apointer to an array that was allocated via a C++new[] expression or be 0.Afterwards, the use count is 1 (even ifp == 0; see~shared_array).
T is a complete type.
std::bad_alloc. If an exception is thrown,delete[] p is called.
template<class D> shared_array(T* p, D d);Constructs ashared_array, storing a copy ofp and ofd.Afterwards, the use count is 1. When the the time comes to delete the arraypointed to byp, the objectd is used in the statementd(p).
T is a complete type.
The copy constructor and destructor ofD must not throw.
Invoking the objectd with parameterp must not throw.
std::bad_alloc. If an exception is thrown,d(p) is called.
shared_array(const shared_array& v) noexcept;Constructs ashared_array, as if by storing a copy of the pointerstored inv. Afterwards, the use count for all copies is 1 more than theinitial use count.
T is a complete type.
~shared_array() noexcept;Decrements the use count. Then, if the use count is 0, deletes thearray pointed to by the stored pointer. Note thatdelete[] on a pointer witha value of 0 is harmless.
shared_array& operator=(const shared_array& v) noexcept;Constructs a newshared_array as described above, then replacesthisshared_array with the new one, destroying the replaced object.
T is a complete type.
*this.
void reset(T* p = 0);Constructs a newshared_array as described above, then replacesthisshared_array with the new one, destroying the replaced object.
T is a complete type.
std::bad_alloc. If an exception is thrown,delete[] p is called.
template<class D> void reset(T* p, D d);Constructs a newshared_array as described above, then replacesthisshared_array with the new one, destroying the replaced object.
T is a complete type.
The copy constructor ofD must not throw.
std::bad_alloc. If an exception is thrown,d(p) is called.
T& operator[](std::ptrdiff_t n) const noexcept;A reference to elementn of the array pointed to by the storedpointer. Behavior is undefined and almost certainly undesirable if the storedpointer is 0, or ifn is less than 0 or is greater than or equal to thenumber of elements in the array.
T is a complete type.
T* get() const noexcept;The stored pointer.
bool unique() const noexcept;true if no othershared_array is sharing ownership of thestored pointer,false otherwise.
long use_count() const noexcept;The number ofshared_array objects sharing ownership of thestored pointer.
explicit operator bool() const noexcept;get() != 0.
T is a complete type.
void swap(shared_array<T>& b) noexcept;Exchanges the contents of the two smart pointers.
template<class T> bool operator==(const shared_array<T>& a, const shared_array<T>& b) noexcept;template<class T> bool operator!=(const shared_array<T>& a, const shared_array<T>& b) noexcept;template<class T> bool operator<(const shared_array<T>& a, const shared_array<T>& b) noexcept;The result of comparing the stored pointers of the two smartpointers.
Note | Theoperator< overload is provided to define an ordering so thatshared_array objects can be used in associative containers such asstd::map. The implementation usesstd::less<T*> to perform the comparison.This ensures that the comparison is handled correctly, since the standardmandates that relational operations on pointers are unspecified (5.9[expr.rel] paragraph 2) butstd::less on pointers is well-defined (20.3.3[lib.comparisons] paragraph 8). |
template<class T> void swap(shared_array<T>& a, shared_array<T>& b) noexcept;a.swap(b).
T is a complete type.
This documentation is
Copyright 1999 Greg Colvin
Copyright 1999 Beman Dawes
Copyright 2002 Darin Adler
Copyright 2003-2017 Peter Dimov
Copyright 2005, 2006 Ion Gaztañaga
Copyright 2008 Frank Mori Hess
Copyright 2012-2017 Glen Fernandes
Copyright 2013 Andrey Semashev
and is distributed under theBoost Software License, Version 1.0.