Header ``intrusive_shared_ptr.h`` ======================================================== The core smart pointer template and its ``std::atomic`` specialization. .. cpp:namespace:: isptr .. cpp:class:: template intrusive_shared_ptr A smart pointer that stores ``T *`` and delegates reference-count manipulation to ``Traits``. .. note:: The template is declared with ``[[clang::trivial_abi]]`` attribute when compiled under Clang. See `trivial_abi `_ for the rationale. **Traits requirements.** ``Traits`` must expose two static methods with the following signatures: .. code-block:: cpp add_ref(T *) noexcept sub_ref(T *) noexcept The return value of either method is ignored. The argument is never ``nullptr``. .. cpp:namespace-push:: template intrusive_shared_ptr Member types ~~~~~~~~~~~~~ .. cpp:type:: pointer = T * The stored pointer type. .. cpp:type:: element_type = T The pointee type. .. cpp:type:: traits_type = Traits The traits in use. Construction, assignment, destruction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. cpp:function:: intrusive_shared_ptr() noexcept intrusive_shared_ptr(std::nullptr_t) noexcept Construct a null pointer. .. cpp:function:: intrusive_shared_ptr(const intrusive_shared_ptr & src) noexcept intrusive_shared_ptr(intrusive_shared_ptr && src) noexcept Copy and move construction from the same type and traits. The move constructor performs no changes to the reference count. .. cpp:function:: template intrusive_shared_ptr(const intrusive_shared_ptr & src) noexcept template intrusive_shared_ptr(intrusive_shared_ptr && src) noexcept Converting copy and move construction from any object of a type ``Y`` such that ``Y *`` is convertible to ``T *``, using the same or different traits. For the move, if the source and destination traits are the same, no changes to the source reference count are performed. .. cpp:function:: intrusive_shared_ptr & operator=(const intrusive_shared_ptr & src) noexcept intrusive_shared_ptr & operator=(intrusive_shared_ptr && src) noexcept template intrusive_shared_ptr & operator=(const intrusive_shared_ptr & src) noexcept template intrusive_shared_ptr & operator=(intrusive_shared_ptr && src) noexcept Copy and move assignment, with the same type/traits and converting overloads as the constructors above. As with the move constructor, a move between identical traits performs no changes to the source reference count. .. cpp:function:: ~intrusive_shared_ptr() noexcept Non-virtual destructor. .. cpp:function:: static intrusive_shared_ptr noref(T * p) noexcept Create a smart pointer from a raw pointer **without** modifying the reference count (attach). .. cpp:function:: static intrusive_shared_ptr ref(T * p) noexcept Create a smart pointer from a raw pointer and **increment** the reference count (retain). Observers ~~~~~~~~~ .. cpp:function:: T * get() const noexcept Return the stored pointer. The reference count is not modified. .. cpp:function:: T * operator->() const noexcept Return the stored pointer. The reference count is not modified. .. cpp:function:: T & operator*() const noexcept Return a reference to the pointee. Undefined if the stored pointer is ``nullptr``. .. cpp:function:: template M & operator->*(M T::*memptr) const noexcept Return the result of ``get()->*memptr``, allowing access through a pointer to member of the pointee. .. cpp:function:: explicit operator bool() const noexcept ``true`` if the pointer is non-null. Modifiers ~~~~~~~~~ .. cpp:function:: T * release() noexcept Release ownership of the stored pointer. The object is set to null and the caller assumes ownership; the reference count is not adjusted. .. cpp:function:: void reset() noexcept Clear the stored pointer, decrementing the reference count. .. cpp:function:: void swap(intrusive_shared_ptr & other) noexcept Swap with another pointer of the same type. See also the non-member :cpp:func:`swap`. .. cpp:function:: output_param get_output_param() noexcept inout_param get_inout_param() noexcept Return a temporary exposing ``operator T**() && noexcept`` that yields a ``T**`` aliasing the smart pointer's internal storage, for passing to C functions that write back a reference-counted pointer. * ``get_output_param`` first resets the pointer to null. Use it for **output** parameters, where the callee returns a freshly counted pointer. * ``get_inout_param`` passes the current value through unchanged. Use it for **in/out** parameters, where the callee both reads and replaces it. .. tip:: In C++23 and later, prefer ``std::out_ptr`` / ``std::inout_ptr`` (enabled by the specializations below) over these methods. .. cpp:namespace-pop:: Non-member functions ~~~~~~~~~~~~~~~~~~~~~~ All of these are ``noexcept``. .. cpp:function:: void swap(intrusive_shared_ptr & lhs, intrusive_shared_ptr & rhs) noexcept Swap two pointers of the same type. Found by ADL only. .. cpp:function:: bool operator==(...) noexcept bool operator!=(...) noexcept Equality and inequality between ``intrusive_shared_ptr`` of compatible types (with any traits), raw pointers, and ``nullptr``. .. cpp:function:: bool operator<(...) noexcept bool operator<=(...) noexcept bool operator>=(...) noexcept bool operator>(...) noexcept Ordering between ``intrusive_shared_ptr`` of compatible types (with any traits) and raw pointers. On C++20 these are replaced by a single ``operator<=>``. .. cpp:function:: size_t hash_value(const intrusive_shared_ptr & ptr) noexcept Hash of the stored pointer value (e.g. for Boost.Hash). .. cpp:function:: template std::basic_ostream & operator<<(std::basic_ostream & str, const intrusive_shared_ptr & ptr) Write the stored pointer value to a stream. Found by ADL only. .. cpp:function:: template Dest intrusive_const_cast(intrusive_shared_ptr src) noexcept template Dest intrusive_static_cast(intrusive_shared_ptr src) noexcept template Dest intrusive_dynamic_cast(intrusive_shared_ptr src) noexcept Perform the equivalent of ``const_cast`` / ``static_cast`` / ``dynamic_cast`` on the argument. ``Dest`` must be a valid ``intrusive_shared_ptr`` type whose underlying type is convertible from the source's via the corresponding cast. ``intrusive_dynamic_cast`` returns a null result if the underlying ``dynamic_cast`` fails. Specializations ~~~~~~~~~~~~~~~~ .. cpp:struct:: template std::out_ptr_t, T *> .. cpp:struct:: template std::inout_ptr_t, T *> Enable ``std::out_ptr`` / ``std::inout_ptr`` with ``intrusive_shared_ptr``. Provided when the standard library offers ```` support. .. cpp:struct:: template std::formatter, CharT> Enable ``std::format`` with ``intrusive_shared_ptr``. Provided when the standard library offers ``std::format`` support. .. cpp:struct:: template std::hash> Enable use as a key in unordered associative containers. .. cpp:class:: template std::atomic> Provides the standard ``std::atomic`` interface for ``intrusive_shared_ptr``. It is **not** lock-free: operations are serialized with an internal lock. .. cpp:type:: value_type = isptr::intrusive_shared_ptr The pointer type being wrapped. .. cpp:member:: static constexpr bool is_always_lock_free Always ``false``. .. rubric:: Construction / assignment .. cpp:function:: constexpr atomic() noexcept Initialize with a null pointer. .. cpp:function:: atomic(value_type desired) noexcept Initialize holding ``desired``. .. cpp:function:: atomic(const atomic &) = delete atomic & operator=(const atomic &) = delete Not copyable. .. cpp:function:: ~atomic() noexcept Releases the held pointer. .. cpp:function:: value_type operator=(value_type desired) noexcept Same as ``store()``. .. cpp:function:: operator value_type() const noexcept Same as ``load()``. .. rubric:: Atomic operations Each behaves like the matching ``std::atomic`` member. .. cpp:function:: value_type load(std::memory_order order = std::memory_order_seq_cst) const noexcept Read the stored pointer. .. cpp:function:: void store(value_type desired, std::memory_order order = std::memory_order_seq_cst) noexcept Replace the stored pointer. .. cpp:function:: value_type exchange(value_type desired, std::memory_order order = std::memory_order_seq_cst) noexcept Replace the stored pointer and return the previous value. .. cpp:function:: bool compare_exchange_strong(value_type & expected, value_type desired, std::memory_order success, std::memory_order failure) noexcept bool compare_exchange_strong(value_type & expected, value_type desired, std::memory_order order = std::memory_order_seq_cst) noexcept Compare and swap. .. cpp:function:: bool compare_exchange_weak(value_type & expected, value_type desired, std::memory_order success, std::memory_order failure) noexcept bool compare_exchange_weak(value_type & expected, value_type desired, std::memory_order order = std::memory_order_seq_cst) noexcept Compare and swap. May fail spuriously. .. cpp:function:: bool is_lock_free() const noexcept Always ``false``.