Intrusive Smart Pointer

#include <dplx/cncr/intrusive_ptr.hpp>
namespace dplx::cncr {}

Concepts

template<typename RC>
concept ref_counted

A type whose lifetime is managed by an internal reference counter and which has a reference_counted_traits specialization for controlling the reference counter.

All functions are required to be noexcept.

Notation

RC &obj

An lvalue reference to a reference counted object.

Valid Expressions

template<typename RC>
concept inspectable_ref_counted

Requires that a ref_counted type also provides a way to get an estimate of the current reference count. Not requiring the value to be excact allows reference counted objects shared across multiple threads to satisfy this.

The only value required to be stable is 1 in which case our thread should be the only pointee. (With the exception of insane software architectures which retain non owning across threads).

All functions are required to be noexcept.

Notation

RC &obj

An lvalue reference to a reference counted object.

Valid Expressions

template<ref_counted RC>
concept detail::dplx_ref_counted

Exposition Only

Describes the typical deeplex reference counting API.

All functions are required to be noexcept.

Notation

RC const &obj

An lvalue reference to a reference counted object.

Valid Expressions

  • obj.add_reference() increments the reference counter.

  • obj.release() decrements the reference counter.

  • obj.reference_count() retrieves the current (approximate) reference count.

Customization Points

template<typename RC>
class reference_counted_traits

This is a customization point i.e. there is no primary template definition.

The implementation requirements are described by the ref_counted and inspectable_ref_counted concepts.

template<detail::dplx_ref_counted RC>
class reference_counted_traits<RC>

The specialization of reference_counted_traits for types satisfying detail::dplx_ref_counted.

The specialization satisfies inspectable_ref_counted.

Factory Functions

template<ref_counted RC>
constexpr auto intrusive_ptr_import(RC *obj) -> intrusive_ptr<RC>

Creates a intrusive_ptr<RC> tracking obj assuming ownership of an existing reference (i.e. it doesn’t call add_reference())

It is a type deducing wrapper around intrusive_ptr<RC>::import.

template<ref_counted RC>
constexpr auto intrusive_ptr_acquire(RC *obj) -> intrusive_ptr<RC>

Creates a intrusive_ptr<RC> tracking obj assuming ownership by acquiring a new reference (i.e. it calls add_reference()).

It is a type deducing wrapper around intrusive_ptr<RC>::acquire.

Types

template<ref_counted RC>
class intrusive_ptr<RC, RC>

The usual intrusive smart pointer which poses as a pointer to the object whose lifetime it manages.

The type satisfies std::regular, i.e. it is default initializable, copyable and equality comparable. It is also swappable, totally ordered and contextually convertible to bool.

Additionally the following members exist:

using element_type = RC

Exposes the type parameter for meta programming purposes.

using handle_type = intrusive_ptr<RC>

Exposes the type which is used for reference counting. It is exposed for compatibility with the aliasing variant intrusive_ptr<T, RC> whose element_type is not equal to RC.

constexpr intrusive_ptr(std::nullptr_t) noexcept

Constructs an empty instance from a nullptr literal which makes the following expressions well formed:

intrusive_ptr<T> ptr{nullptr};
ptr = nullptr;
template<ref_counted U>
constexpr intrusive_ptr(intrusive_ptr<U> &&other) noexcept

Imports ownership from a compatible intrusive_ptr<U> instance.

This constructor is only available if std::convertible_to<U*, RC*> holds.

template<ref_counted U>
constexpr intrusive_ptr(intrusive_ptr<U> const &other) noexcept

Aquires ownership from a compatible intrusive_ptr<U> instance.

This constructor is only available if std::convertible_to<U*, RC*> holds.

static constexpr auto import(RC *ptr) noexcept -> intrusive_ptr<RC>

Creates a intrusive_ptr<RC> tracking ptr assuming ownership of an existing reference (i.e. it doesn’t call add_reference()).

static constexpr auto acquire(RC *ptr) noexcept -> intrusive_ptr<RC>

Creates a intrusive_ptr<RC> tracking ptr assuming ownership by acquiring a new reference (i.e. it calls add_reference()).

constexpr auto get() const noexcept -> RC*

Retrieves the stored object pointer.

constexpr auto get_handle() const noexcept -> intrusive_ptr<RC>

Returns a copy of this. It is exposed for compatibility with the aliasing variant intrusive_ptr<T, RC> whose element_type is not equal to RC.

constexpr auto use_count() const noexcept -> reference_counted_traits<RC>::counter_type
constexpr auto reference_count() const noexcept -> reference_counted_traits<RC>::counter_type

If RC satisfies inspectable_ref_counted it returns the (approximate) number of references. The only value guaranteed to be stable in multi-threaded environments is 1.

The use_count() name exists for API compatibility with std::shared_ptr.

constexpr auto release() noexcept -> RC*

Returns the bound object after unbinding this without decrementing the reference counter.

constexpr void reset(RC *toBeBound) noexcept

Replaces the managed object with toBeBound and increases its ref count.

template<>
class intrusive_ptr<void, void>

A type erased intrusive pointer. It keeps a pointer to a vtable in addition to a void * referencing the bound object.

The type satisfies std::regular, i.e. it is default initializable, copyable and equality comparable. It is also swappable, totally ordered and contextually convertible to bool.

You can either (copy) assign normal intrusive pointer instances or use the static class functions import or acquire

Additionally the following members exist:

using element_type = void

Exposes the type parameter for meta programming purposes.

using handle_type = intrusive_ptr<void, void>

Exposes the type which is used for reference counting. It is exposed for compatibility with the aliasing variant intrusive_ptr<T, RC> whose element_type is not equal to void.

intrusive_ptr(std::nullptr_t) noexcept

Constructs an empty instance from a nullptr literal which makes the following expressions well formed:

intrusive_ptr<void> ptr{nullptr};
ptr = nullptr;
template<ref_counted U>
intrusive_ptr(intrusive_ptr<U> &&other) noexcept

Imports ownership from an intrusive_ptr<U> instance.

template<ref_counted U>
intrusive_ptr(intrusive_ptr<U> const &other) noexcept

Aquires ownership from an intrusive_ptr<U> instance.

template<ref_counted RC>
static auto import(RC *ptr) noexcept -> intrusive_ptr<void, void>

Creates a intrusive_ptr<void, void> tracking ptr assuming ownership of an existing reference (i.e. it doesn’t call add_reference()).

template<ref_counted RC>
static auto acquire(RC *ptr) noexcept -> intrusive_ptr<void, void>

Creates a intrusive_ptr<void, void> tracking ptr assuming ownership by acquiring a new reference (i.e. it calls add_reference()).

auto get() const noexcept -> void*

Retrieves the stored object pointer.

auto get_handle() const noexcept -> intrusive_ptr<void>

Returns a copy of this. It is exposed for compatibility with the aliasing variant intrusive_ptr<T, RC> whose element_type is not equal to void.

template<ref_counted U>
auto release_as() noexcept -> U*

Returns the bound object pointer after casting it to U after unbinding this without decrementing the reference counter.

template<typename T, ref_counted RC = T>
class intrusive_ptr

The main template is an aliasing intrusive pointer which means it poses as a pointer to an object of type T while managing the reference count of (a potentially different) object of type RC.

The type satisfies std::regular, i.e. it is default initializable, copyable and equality comparable. It is also swappable, totally ordered and contextually convertible to bool.

Additionally the following members exist:

using element_type = T

Exposes the type parameter for meta programming purposes.

using handle_type = intrusive_ptr<RC>

Exposes the intrusive pointer type which implements reference counting.

constexpr intrusive_ptr(std::nullptr_t) noexcept

Constructs an empty instance from a nullptr literal which makes the following expressions well formed:

intrusive_ptr<T, RC> ptr{nullptr};
ptr = nullptr;
constexpr intrusive_ptr(intrusive_ptr<RC> &&handle, T *ptr) noexcept

Creates a intrusive_ptr<T, RC> tracking handle assuming ownership of an existing reference (i.e. it doesn’t call add_reference()).

The constructed intrusive pointer poses as ptr afterwards.

constexpr intrusive_ptr(intrusive_ptr<RC> const &handle, T *ptr) noexcept

Creates a intrusive_ptr<T, RC> tracking handle assuming ownership by acquiring a new reference (i.e. it calls add_reference()).

The constructed intrusive pointer poses as ptr afterwards.

constexpr auto get() const noexcept -> T*

Retrieves the stored aliased object pointer.

constexpr auto get_handle() const noexcept -> intrusive_ptr<RC>

Returns a copy of the contained object handle.

constexpr auto use_count() const noexcept -> reference_counted_traits<RC>::counter_type
constexpr auto reference_count() const noexcept -> reference_counted_traits<RC>::counter_type

If RC satisfies inspectable_ref_counted it returns the (approximate) number of references. The only value guaranteed to be stable in multi-threaded environments is 1.

The use_count() name exists for API compatibility with std::shared_ptr.