//// Copyright 2017 Peter Dimov Distributed under the Boost Software License, Version 1.0. See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt //// [#local_shared_ptr] # local_shared_ptr: Shared Ownership within a Single Thread :toc: :toc-title: :idprefix: local_shared_ptr_ ## Description `local_shared_ptr` is nearly identical to `shared_ptr`, with the only difference of note being that its reference count is updated with non-atomic operations. As such, a `local_shared_ptr` and all its copies must reside in (be local to) a single thread (hence the name.) `local_shared_ptr` can be converted to `shared_ptr` and vice versa. Creating a `local_shared_ptr` from a `shared_ptr` creates a new local reference count; this means that two `local_shared_ptr` instances, both created from the same `shared_ptr`, refer to the same object but don't share the same count, and as such, can safely be used by two different threads. .Two local_shared_ptr instances created from a shared_ptr ``` shared_ptr p1( new X ); local_shared_ptr p2( p1 ); // p2.local_use_count() == 1 local_shared_ptr p3( p1 ); // p3.local_use_count() also 1 ``` Creating the second `local_shared_ptr` from the first one, however, does lead to the two sharing the same count: .A local_shared_ptr created from another local_shared_ptr ``` shared_ptr p1( new X ); local_shared_ptr p2( p1 ); // p2.local_use_count() == 1 local_shared_ptr p3( p2 ); // p3.local_use_count() == 2 ``` Two `shared_ptr` instances created from the same `local_shared_ptr` do share ownership: .Two shared_ptr instances created from a local_shared_ptr ``` local_shared_ptr p1( new X ); shared_ptr p2( p1 ); // p2.use_count() == 2 shared_ptr p3( p1 ); // p3.use_count() == 3 ``` Here `p2.use_count()` is 2, because `p1` holds a reference, too. One can think of `local_shared_ptr` as `shared_ptr>`, with the outer `shared_ptr` using non-atomic operations for its count. Converting from `local_shared_ptr` to `shared_ptr` gives you a copy of the inner `shared_ptr`; converting from `shared_ptr` wraps it into an outer `shared_ptr` with a non-atomic use count (conceptually speaking) and returns the result. ## Synopsis `local_shared_ptr` is defined in ``. ``` namespace boost { template 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 explicit local_shared_ptr(Y * p); template local_shared_ptr(Y * p, D d); template local_shared_ptr(std::nullptr_t p, D d); template local_shared_ptr(Y * p, D d, A a); template local_shared_ptr(std::nullptr_t p, D d, A a); local_shared_ptr(local_shared_ptr const & r) noexcept; template local_shared_ptr(local_shared_ptr const & r) noexcept; local_shared_ptr(local_shared_ptr && r) noexcept; template local_shared_ptr(local_shared_ptr && r) noexcept; template local_shared_ptr( shared_ptr const & r ); template local_shared_ptr( shared_ptr && r ); template local_shared_ptr(local_shared_ptr const & r, element_type * p) noexcept; template local_shared_ptr(local_shared_ptr && r, element_type * p) noexcept; template local_shared_ptr(std::unique_ptr && r); // destructor ~local_shared_ptr() noexcept; // assignment local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; template local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; local_shared_ptr & operator=(local_shared_ptr const && r) noexcept; template local_shared_ptr & operator=(local_shared_ptr const && r) noexcept; template local_shared_ptr & operator=(std::unique_ptr && r); local_shared_ptr & operator=(std::nullptr_t) noexcept; // reset void reset() noexcept; template void reset(Y * p); template void reset(Y * p, D d); template void reset(Y * p, D d, A a); template void reset(local_shared_ptr const & r, element_type * p) noexcept; template void reset(local_shared_ptr && 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 operator shared_ptr() const noexcept; template operator weak_ptr() const noexcept; // swap void swap(local_shared_ptr & b) noexcept; // owner_before template bool owner_before(local_shared_ptr const & rhs) const noexcept; }; // comparisons template bool operator==(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; template bool operator==(local_shared_ptr const & a, shared_ptr const & b) noexcept; template bool operator==(shared_ptr const & a, local_shared_ptr const & b) noexcept; template bool operator!=(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; template bool operator!=(local_shared_ptr const & a, shared_ptr const & b) noexcept; template bool operator!=(shared_ptr const & a, local_shared_ptr const & b) noexcept; template bool operator==(local_shared_ptr const & p, std::nullptr_t) noexcept; template bool operator==(std::nullptr_t, local_shared_ptr const & p) noexcept; template bool operator!=(local_shared_ptr const & p, std::nullptr_t) noexcept; template bool operator!=(std::nullptr_t, local_shared_ptr const & p) noexcept; template bool operator<(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; // swap template void swap(local_shared_ptr & a, local_shared_ptr & b) noexcept; // get_pointer template typename local_shared_ptr::element_type * get_pointer(local_shared_ptr const & p) noexcept; // casts template local_shared_ptr static_pointer_cast(local_shared_ptr const & r) noexcept; template local_shared_ptr const_pointer_cast(local_shared_ptr const & r) noexcept; template local_shared_ptr dynamic_pointer_cast(local_shared_ptr const & r) noexcept; template local_shared_ptr reinterpret_pointer_cast(local_shared_ptr const & r) noexcept; // stream I/O template std::basic_ostream & operator<< (std::basic_ostream & os, local_shared_ptr const & p); // get_deleter template D * get_deleter(local_shared_ptr const & p) noexcept; } ``` ## Members ### element_type ``` typedef ... element_type; ``` `element_type` is `T` when `T` is not an array type, and `U` when `T` is `U[]` or `U[N]`. ### default constructor ``` constexpr local_shared_ptr() noexcept; ``` ``` constexpr local_shared_ptr(std::nullptr_t) noexcept; ``` [none] * {blank} + Effects:: Constructs an empty `local_shared_ptr`. Postconditions:: `local_use_count() == 0 && get() == 0`. ### pointer constructor ``` template explicit local_shared_ptr(Y * p); ``` [none] * {blank} + Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p )`. Postconditions:: `local_use_count() == 1 && get() == p`. Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. ### constructors taking a deleter ``` template local_shared_ptr(Y * p, D d); ``` ``` template local_shared_ptr(std::nullptr_t p, D d); ``` [none] * {blank} + Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p, d )`. Postconditions:: `local_use_count() == 1 && get() == p`. Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. ``` template local_shared_ptr(Y * p, D d, A a); ``` ``` template local_shared_ptr(std::nullptr_t p, D d, A a); ``` [none] * {blank} + Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p, d, a )`. Postconditions:: `local_use_count() == 1 && get() == p`. Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. ### copy and converting constructors ``` local_shared_ptr(local_shared_ptr const & r) noexcept; ``` ``` template local_shared_ptr(local_shared_ptr const & r) noexcept; ``` [none] * {blank} + Requires:: `Y*` should be convertible to `T*`. Effects:: If `r` is empty, constructs an empty `local_shared_ptr`; otherwise, constructs a `local_shared_ptr` that shares ownership with `r`. Postconditions:: `get() == r.get() && local_use_count() == r.local_use_count()`. ### move constructors ``` local_shared_ptr(local_shared_ptr && r) noexcept; ``` ``` template local_shared_ptr(local_shared_ptr && r) noexcept; ``` [none] * {blank} + Requires:: `Y*` should be convertible to `T*`. Effects:: Move-constructs a `local_shared_ptr` from `r`. Postconditions:: `*this` contains the old value of `r`. `r` is empty and `r.get() == 0`. ### shared_ptr constructor ``` template local_shared_ptr( shared_ptr const & r ); ``` ``` template local_shared_ptr( shared_ptr && r ); ``` [none] * {blank} + Effects:: Constructs a `local_shared_ptr` that owns `r`. Postconditions:: `local_use_count() == 1`. `get()` returns the old value of `r.get()`. Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. ### aliasing constructor ``` template local_shared_ptr(local_shared_ptr const & r, element_type * p) noexcept; ``` [none] * {blank} + Effects:: constructs a `local_shared_ptr` that shares ownership with `r` and stores `p`. Postconditions:: `get() == p && local_use_count() == r.local_use_count()`. ### aliasing move constructor ``` template local_shared_ptr(local_shared_ptr && r, element_type * p) noexcept; ``` [none] * {blank} + Effects:: Move-constructs a `local_shared_ptr` from `r`, while storing `p` instead. Postconditions:: `get() == p` and `local_use_count()` equals the old count of `r`. `r` is empty and `r.get() == 0`. ### unique_ptr constructor ``` template local_shared_ptr(std::unique_ptr && r); ``` [none] * {blank} + Requires:: `Y*` should be convertible to `T*`. Effects:: - When `r.get() == 0`, equivalent to `local_shared_ptr()`; - Otherwise, constructs a `local_shared_ptr` that owns `shared_ptr( std::move(r) )`. Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. Exception safety:: If an exception is thrown, the constructor has no effect. ### destructor ``` ~local_shared_ptr() noexcept; ``` [none] * {blank} + Effects:: - If `*this` is empty, or shares ownership with another `local_shared_ptr` instance (`local_use_count() > 1`), there are no side effects. - Otherwise, destroys the owned `shared_ptr`. ### assignment ``` local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; ``` ``` template local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr(r).swap(*this)`. Returns:: `*this`. ``` local_shared_ptr & operator=(local_shared_ptr && r) noexcept; ``` ``` template local_shared_ptr & operator=(local_shared_ptr && r) noexcept; ``` ``` template local_shared_ptr & operator=(std::unique_ptr && r); ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr(std::move(r)).swap(*this)`. Returns:: `*this`. ``` local_shared_ptr & operator=(std::nullptr_t) noexcept; ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr().swap(*this)`. Returns:: `*this`. ### reset ``` void reset() noexcept; ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr().swap(*this)`. ``` template void reset(Y * p); ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr(p).swap(*this)`. ``` template void reset(Y * p, D d); ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr(p, d).swap(*this)`. ``` template void reset(Y * p, D d, A a); ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr(p, d, a).swap(*this)`. ``` template void reset(local_shared_ptr const & r, element_type * p) noexcept; ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr(r, p).swap(*this)`. ``` template void reset(local_shared_ptr && r, element_type * p) noexcept; ``` [none] * {blank} + Effects:: Equivalent to `local_shared_ptr(std::move(r), p).swap(*this)`. ### indirection ``` T & operator*() const noexcept; ``` [none] * {blank} + Requires:: `T` should not be an array type. Returns:: `*get()`. ``` T * operator->() const noexcept; ``` [none] * {blank} + Requires:: `T` should not be an array type. Returns:: `get()`. ``` element_type & operator[](std::ptrdiff_t i) const noexcept; ``` [none] * {blank} + Requires:: `T` should be an array type. The stored pointer must not be 0. `i >= 0`. If `T` is `U[N]`, `i < N`. Returns:: `get()[i]`. ### get ``` element_type * get() const noexcept; ``` [none] * {blank} + Returns:: The stored pointer. ### local_use_count ``` long local_use_count() const noexcept; ``` [none] * {blank} + Returns:: The number of `local_shared_ptr` objects, `*this` included, that share ownership with `*this`, or 0 when `*this` is empty. ### conversions ``` explicit operator bool() const noexcept; ``` [none] * {blank} + Returns:: `get() != 0`. NOTE: On C++03 compilers, the return value is of an unspecified type. ``` template operator shared_ptr() const noexcept; ``` ``` template operator weak_ptr() const noexcept; ``` [none] * {blank} + Requires:: `T*` should be convertible to `Y*`. Returns:: a copy of the owned `shared_ptr`. ### swap ``` void swap(local_shared_ptr & b) noexcept; ``` [none] * {blank} + Effects:: Exchanges the contents of the two smart pointers. ### owner_before ``` template bool owner_before(local_shared_ptr const & rhs) const noexcept; ``` [none] * {blank} + Effects:: See the description of `operator<`. ## Free Functions ### comparison ``` template bool operator==(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; ``` ``` template bool operator==(local_shared_ptr const & a, shared_ptr const & b) noexcept; ``` ``` template bool operator==(shared_ptr const & a, local_shared_ptr const & b) noexcept; ``` [none] * {blank} + Returns:: `a.get() == b.get()`. ``` template bool operator!=(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; ``` ``` template bool operator!=(local_shared_ptr const & a, shared_ptr const & b) noexcept; ``` ``` template bool operator!=(shared_ptr const & a, local_shared_ptr const & b) noexcept; ``` [none] * {blank} + Returns:: `a.get() != b.get()`. ``` template bool operator==(local_shared_ptr const & p, std::nullptr_t) noexcept; ``` ``` template bool operator==(std::nullptr_t, local_shared_ptr const & p) noexcept; ``` [none] * {blank} + Returns:: `p.get() == 0`. ``` template bool operator!=(local_shared_ptr const & p, std::nullptr_t) noexcept; ``` ``` template bool operator!=(std::nullptr_t, local_shared_ptr const & p) noexcept; ``` [none] * {blank} + Returns:: `p.get() != 0`. ``` template bool operator<(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; ``` [none] * {blank} + Returns:: An unspecified value such that - `operator<` is a strict weak ordering as described in section [lib.alg.sorting] of the {cpp} standard; - under the equivalence relation defined by `operator<`, `!(a < b) && !(b < a)`, two `local_shared_ptr` instances are equivalent if and only if they share ownership or are both empty. NOTE: Allows `local_shared_ptr` objects to be used as keys in associative containers. NOTE: The rest of the comparison operators are omitted by design. ### swap ``` template void swap(local_shared_ptr & a, local_shared_ptr & b) noexcept; ``` [none] * {blank} + Effects:: Equivalent to `a.swap(b)`. ### get_pointer ``` template typename local_shared_ptr::element_type * get_pointer(local_shared_ptr const & p) noexcept; ``` [none] * {blank} + Returns:: `p.get()`. NOTE: Provided as an aid to generic programming. Used by `mem_fn`. ### static_pointer_cast ``` template local_shared_ptr static_pointer_cast(local_shared_ptr const & r) noexcept; ``` [none] * {blank} + Requires:: The expression `static_cast( (U*)0 )` must be well-formed. Returns:: `local_shared_ptr( r, static_cast::element_type*>(r.get()) )`. CAUTION: The seemingly equivalent expression `local_shared_ptr(static_cast(r.get()))` will eventually result in undefined behavior, attempting to delete the same object twice. ### const_pointer_cast ``` template local_shared_ptr const_pointer_cast(local_shared_ptr const & r) noexcept; ``` [none] * {blank} + Requires:: The expression `const_cast( (U*)0 )` must be well-formed. Returns:: `local_shared_ptr( r, const_cast::element_type*>(r.get()) )`. ### dynamic_pointer_cast ``` template local_shared_ptr dynamic_pointer_cast(local_shared_ptr const & r) noexcept; ``` [none] * {blank} + Requires:: The expression `dynamic_cast( (U*)0 )` must be well-formed. Returns:: - When `dynamic_cast::element_type*>(r.get())` returns a nonzero value `p`, `local_shared_ptr(r, p)`; - Otherwise, `local_shared_ptr()`. ### reinterpret_pointer_cast ``` template local_shared_ptr reinterpret_pointer_cast(local_shared_ptr const & r) noexcept; ``` [none] * {blank} + Requires:: The expression `reinterpret_cast( (U*)0 )` must be well-formed. Returns:: `local_shared_ptr( r, reinterpret_cast::element_type*>(r.get()) )`. ### operator<< ``` template std::basic_ostream & operator<< (std::basic_ostream & os, local_shared_ptr const & p); ``` [none] * {blank} + Effects:: `os << p.get();`. Returns:: `os`. ### get_deleter ``` template D * get_deleter(local_shared_ptr const & p) noexcept; ``` [none] * {blank} + Returns:: If `*this` owns a `shared_ptr` instance `p`, `get_deleter( p )`, otherwise 0.