diff --git a/doc/smart_ptr/intrusive_ptr.adoc b/doc/smart_ptr/intrusive_ptr.adoc index c22a128..3dd7047 100644 --- a/doc/smart_ptr/intrusive_ptr.adoc +++ b/doc/smart_ptr/intrusive_ptr.adoc @@ -1,5 +1,5 @@ //// -Copyright 2017 Peter Dimov +Copyright 2003-2005, 2013, 2017 Peter Dimov Distributed under the Boost Software License, Version 1.0. @@ -13,3 +13,435 @@ http://www.boost.org/LICENSE_1_0.txt :toc-title: :idprefix: intrusive_ptr_ +## Introduction + +The `intrusive_ptr` class template stores a pointer to an object with an embedded reference count. +Every new `intrusive_ptr` instance increments the reference count by using an unqualified call to the +function `intrusive_ptr_add_ref`, passing it the pointer as an argument. Similarly, when an `intrusive_ptr` +is destroyed, it calls `intrusive_ptr_release`; this function is responsible for destroying the object when +its 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` and `intrusive_ptr_release` should +be defined in the namespace that corresponds to their parameter; otherwise, the definitions need to go in namespace +`boost`. The library provides a helper base class template `<>` which +may help adding support for `intrusive_ptr` to user types. + +The class template is parameterized on `T`, the type of the object pointed to. `intrusive_ptr` can be implicitly +converted to `intrusive_ptr` whenever `T*` can be implicitly converted to `U*`. + +The main reasons to use `intrusive_ptr` are: + +* Some existing frameworks or OSes provide objects with embedded reference counts; +* The memory footprint of `intrusive_ptr` is the same as the corresponding raw pointer; +* `intrusive_ptr` can be constructed from an arbitrary raw pointer of type `T*`. + +As a general rule, if it isn't obvious whether `intrusive_ptr` better fits your needs than `shared_ptr`, try a `shared_ptr`-based design first. + +## Synopsis + +``` +namespace boost +{ + +template 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 intrusive_ptr(intrusive_ptr const & r); + + ~intrusive_ptr(); + + intrusive_ptr & operator=(intrusive_ptr const & r); + template intrusive_ptr & operator=(intrusive_ptr 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; + + operator unspecified-bool-type() const noexcept; + + void swap(intrusive_ptr & b) noexept; +}; + +template +bool operator==(intrusive_ptr const & a, intrusive_ptr const & b) noexcept; + +template +bool operator!=(intrusive_ptr const & a, intrusive_ptr const & b) noexcept; + +template +bool operator==(intrusive_ptr const & a, U * b) noexcept; + +template +bool operator!=(intrusive_ptr const & a, U * b) noexcept; + +template +bool operator==(T * a, intrusive_ptr const & b) noexcept; + +template +bool operator!=(T * a, intrusive_ptr const & b) noexcept; + +template +bool operator<(intrusive_ptr const & a, intrusive_ptr const & b) noexcept; + +template void swap(intrusive_ptr & a, intrusive_ptr & b) noexcept; + +template T * get_pointer(intrusive_ptr const & p) noexcept; + +template +intrusive_ptr static_pointer_cast(intrusive_ptr const & r) noexcept; + +template +intrusive_ptr const_pointer_cast(intrusive_ptr const & r) noexcept; + +template +intrusive_ptr dynamic_pointer_cast(intrusive_ptr const & r) noexcept; + +template +std::basic_ostream & operator<< (std::basic_ostream & os, + intrusive_ptr const & p); + +} // namespace boost +``` + +## Members + +### element_type + +``` +typedef T element_type; +``` + +Provides the type of the template parameter T. + +### constructors + +``` +intrusive_ptr() noexcept; +``` + +[none] +* {blank} ++ +Postconditions:: `get() == 0`. + +``` +intrusive_ptr(T * p, bool add_ref = true); +``` + +[none] +* {blank} ++ +Effects:: `if(p != 0 && add_ref) intrusive_ptr_add_ref(p);`. +Postconditions:: `get() == p`. + +``` +intrusive_ptr(intrusive_ptr const & r); +``` +``` +template intrusive_ptr(intrusive_ptr const & r); +``` + +[none] +* {blank} ++ +Effects:: `if(r.get() != 0) intrusive_ptr_add_ref(r.get());`. +Postconditions:: `get() == r.get()`. + +### destructor + +``` +~intrusive_ptr(); +``` + +[none] +* {blank} ++ +Effects:: `if(get() != 0) intrusive_ptr_release(get());`. + +### assignment + +``` +intrusive_ptr & operator=(intrusive_ptr const & r); +``` +``` +template intrusive_ptr & operator=(intrusive_ptr const & r); +``` +``` +intrusive_ptr & operator=(T * r); +``` + +[none] +* {blank} ++ +Effects:: Equivalent to `intrusive_ptr(r).swap(*this)`. +Returns:: `*this`. + +### reset + +``` +void reset(); +``` + +[none] +* {blank} ++ +Effects:: Equivalent to `intrusive_ptr().swap(*this)`. + +``` +void reset(T * r); +``` + +[none] +* {blank} ++ +Effects:: Equivalent to `intrusive_ptr(r).swap(*this)`. + +``` +void reset(T * r, bool add_ref); +``` + +[none] +* {blank} ++ +Effects:: Equivalent to `intrusive_ptr(r, add_ref).swap(*this)`. + +### indirection + +``` +T & operator*() const noexcept; +``` + +[none] +* {blank} ++ +Requirements:: `get() != 0`. +Returns:: `*get()`. + +``` +T * operator->() const noexcept; +``` + +[none] +* {blank} ++ +Requirements:: `get() != 0`. +Returns:: `get()`. + +### get + +``` +T * get() const noexcept; +``` + +[none] +* {blank} ++ +Returns:: the stored pointer. + +### detach + +``` +T * detach() noexcept; +``` + +[none] +* {blank} ++ +Returns:: the stored pointer. +Postconditions:: `get() == 0`. + +NOTE: The returned pointer has an elevated reference count. This allows conversion of an `intrusive_ptr` +back 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: Using `detach` escapes the safety of automatic reference counting provided by `intrusive_ptr`. +It should by used only where strictly necessary (such as when interfacing to an existing API), and when +the implications are thoroughly understood. + +### conversions + +``` +operator unspecified-bool-type () const noexcept; +``` + +[none] +* {blank} ++ +Returns:: an unspecified value that, when used in boolean contexts, is equivalent to `get() != 0`. + +NOTE: This conversion operator allows `intrusive_ptr` objects to be used in boolean contexts, +like `if (p && p\->valid()) {}`. The actual target type is typically a pointer to a member function, +avoiding many of the implicit conversion pitfalls. + +### swap + +``` +void swap(intrusive_ptr & b) noexcept; +``` + +[none] +* {blank} ++ +Effects:: Exchanges the contents of the two smart pointers. + +## Free Functions + +### comparison + +``` +template +bool operator==(intrusive_ptr const & a, intrusive_ptr const & b) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `a.get() == b.get()`. + +``` +template +bool operator!=(intrusive_ptr const & a, intrusive_ptr const & b) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `a.get() != b.get()`. + +``` +template +bool operator==(intrusive_ptr const & a, U * b) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `a.get() == b`. + +``` +template +bool operator!=(intrusive_ptr const & a, U * b) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `a.get() != b`. + +``` +template +bool operator==(T * a, intrusive_ptr const & b) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `a == b.get()`. + +``` +template +bool operator!=(T * a, intrusive_ptr const & b) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `a != b.get()`. + +``` +template +bool operator<(intrusive_ptr const & a, intrusive_ptr const & b) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `std::less()(a.get(), b.get())`. + +NOTE: Allows `intrusive_ptr` objects to be used as keys in associative containers. + +### swap + +``` +template void swap(intrusive_ptr & a, intrusive_ptr & b) noexcept; +``` + +[none] +* {blank} ++ +Effects:: Equivalent to `a.swap(b)`. + +### get_pointer + +``` +template T * get_pointer(intrusive_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 +intrusive_ptr static_pointer_cast(intrusive_ptr const & r) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `intrusive_ptr(static_cast(r.get()))`. + +### const_pointer_cast + +``` +template +intrusive_ptr const_pointer_cast(intrusive_ptr const & r) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `intrusive_ptr(const_cast(r.get()))`. + +### dynamic_pointer_cast + +``` +template +intrusive_ptr dynamic_pointer_cast(intrusive_ptr const & r) noexcept; +``` + +[none] +* {blank} ++ +Returns:: `intrusive_ptr(dynamic_cast(r.get()))`. + +### operator<< + +``` +template +std::basic_ostream & operator<< (std::basic_ostream & os, + intrusive_ptr const & p); +``` + +[none] +* {blank} ++ +Effects:: `os << p.get();`. +Returns:: `os`.