Header ref_counted.h¶
Reusable CRTP base classes that turn an ordinary class into a reference-counted one, with optional weak-reference and single-threaded support.
Flags¶
-
enum class ref_counted_flags : unsigned¶
Options controlling a
ref_countedinstantiation. Values can be combined with bitwiseOR.-
enumerator none = 0¶
No options (the default).
-
enumerator provide_weak_references = 1¶
Enable weak references.
-
enumerator single_threaded = 2¶
Enable single-threaded mode.
-
enumerator none = 0¶
Class isptr::ref_counted¶
-
template<class Derived, ref_counted_flags Flags = ref_counted_flags::none, class CountType = default_count_type<Flags>>
class ref_counted¶ Base class for any class you want to make reference-counted. It is normally used together with the Header refcnt_ptr.h specialization of
intrusive_shared_ptr, but can also be driven by manual reference-counting calls or other smart pointers.It uses CRTP to reach the derived class, avoiding virtual-function overhead, so the first template parameter
Derivedmust be the name of the derived class. The remaining parameters customize behaviour and are described below.
Customization¶
Weak references (default: off). Weak-reference support adds a small overhead even for objects that never take a weak reference, so it is opt-in. It also forces the count type to
intptr_t.Single-threaded mode (default: off). Reference-count updates are not thread-safe, so such objects cannot be shared across threads, but counting is faster.
Count type (default:
int). Customizable only when weak references are not enabled; must be a signed integral type. Use a smaller type to shrink derived objects when the maximum count is known to be small. With weak references the type is alwaysintptr_t.Many methods are reached through CRTP calls to
Derivedand can therefore be “overridden” by declaring a method of the same name in the derived class. In particular,destroy()is called when the count reaches 0; the default callsdeleteon theDerivedpointer, and overriding it lets you manage differently-allocated objects.
Flags is a combination of ref_counted_flags. CountType (when
provide_weak_references is not set) selects the count type; its default,
default_count_type<Flags>, is int without weak references and
intptr_t with them.
Convenience aliases¶
-
template<class Derived>
using weak_ref_counted = ref_counted<Derived, ref_counted_flags::provide_weak_references>¶ ref_countedwith weak references enabled.
-
template<class Derived, class CountType = default_count_type<ref_counted_flags::single_threaded>>
using ref_counted_st = ref_counted<Derived, ref_counted_flags::single_threaded, CountType>¶ ref_countedin single-threaded mode (CountTypedefaults toint).
-
template<class Derived>
using weak_ref_counted_st = ref_counted<Derived, ref_counted_flags::provide_weak_references | ref_counted_flags::single_threaded>¶ ref_countedwith both weak references and single-threaded mode.
ref_counted_adapter and ref_counted_wrapper expose the
analogous families: weak_ref_counted_adapter / ref_counted_adapter_st /
weak_ref_counted_adapter_st and weak_ref_counted_wrapper /
ref_counted_wrapper_st / weak_ref_counted_wrapper_st.
Usage¶
Derive from ref_counted and make it a friend. Keep your destructor private or
protected. Reference-counted objects must be destroyed through the count, not by
a direct delete.
class foo : public ref_counted<foo>
{
friend ref_counted;
private:
~foo() noexcept = default;
};
Rules for constructors and destructors¶
Warning
Never increment the reference count in the destructor (e.g. by making a
refcnt_ptrfromthis). It trips an assert in debug builds and is undefined behaviour in release. Creating weak references tothisin the destructor is fine.Never hand out
this(or a weak reference to it) from a constructor if later code in that constructor can throw. On exception the object fails to construct, leaving outside code with an invalid pointer. This is a general C++ rule that reference counting does not lift. Handing outthisis fine if no subsequent constructor code can throw.Your destructor must not throw. The counting machinery does not expect it and will break.
If your class is itself a base, its destructor must be
virtual.ref_countedinvokes the destructor of theDerivedargument. (Not applicable ifDerivedis the most-derived class.)
Limitations¶
Without weak references the implementation is standard, portable, and limited
only by requiring the live reference count to stay within
[0, std::numeric_limits<CountType>::max()].
With weak references it multiplexes a pointer and the count in one word, which
assumes: two’s-complement arithmetic; alignof(intptr_t) > 1; and that a
pointer to an over-aligned object has its lowest bit clear when cast to
uintptr_t. These hold on all current platforms.
Member types¶
-
using ref_counted_base = ref_counted¶
A synonym for the class itself, letting derived types refer to it as
Derived::ref_counted_basewithout spelling out the template arguments.
-
type weak_value_type¶
The weak-reference object type this class exposes if weak references are enabled; otherwise
void.
-
type weak_ptr¶
refcnt_ptr<weak_value_type>if weak references are enabled; otherwisevoid.
-
type const_weak_ptr¶
refcnt_ptr<const weak_value_type>if weak references are enabled; otherwisevoid.
Constants¶
-
static constexpr bool provides_weak_references¶
trueif this class provides weak references.
-
static constexpr bool single_threaded¶
trueif this class is single-threaded.
Methods¶
Unless noted otherwise, all methods are noexcept. The copy and move
constructors and assignment operators are deleted (this is a base class, so
slicing would be meaningless). The default constructor is protected and sets
the reference count to 1; the destructor is protected as well.
-
void add_ref() const noexcept¶
Increment the reference count. Overridable.
-
void sub_ref() const noexcept¶
Decrement the reference count and destroy the object when it reaches 0. Overridable.
-
void destroy() const noexcept¶
Protected. Called when the count reaches 0; the default calls
deleteon theDerivedpointer. Overridable.
-
weak_ptr get_weak_ptr()¶
-
const_weak_ptr get_weak_ptr() const¶
Obtain a weak pointer to this object (weak-reference builds only). Not
noexcept: the control block is created lazily on first use, so allocation or a custom weak-reference constructor may throw. Later calls do not throw.
-
const weak_value_type *get_weak_value() const¶
Protected, not
noexcept. The actual retrieval of the raw weak-reference pointer behindget_weak_ptr(). Overridable.
-
weak_value_type *make_weak_reference(intptr_t count) const¶
Protected, not
noexcept(it allocates). Creates the control block on first use; the returned pointer already has its own count incremented. Overridable. See Customizing the weak reference type.
Customizing the weak reference type¶
You can change the weak-reference type by “overriding”
make_weak_reference(). ref_counted looks via CRTP for
a member of this form in your derived class:
some_type * make_weak_reference(intptr_t count) const
where some_type derives from weak_reference. If present, it is
called instead of the built-in one and its return type becomes the weak-reference
type.
Class isptr::weak_reference¶
-
template<class Owner>
class weak_reference¶ The control block representing a weak reference to a
ref_countedclass. Usually used as-is, but can serve as a base for a customized control block.Owneris the class it refers to.Internally it is reference-counted itself and also manages the count of the referenced object; instances are created on demand when the first weak reference is requested.
Customization¶
Derive your own class from weak_reference and pair it with your
ref_counted class (see Customizing the weak reference type). As with
ref_counted, several methods are reached via CRTP and can be overridden; in
particular destroy() defaults to delete on your
class pointer.
Usage¶
You rarely name weak_reference directly. It is available as the
weak_value_type of your ref_counted class. With refcnt_ptr you
convert between strong and weak pointers like so:
auto original = refcnt_attach(new your_object());
auto weak = weak_cast(original);
// or: your_object::weak_ptr weak = weak_cast(original);
auto strong = strong_cast(weak);
assert(strong == original || strong == nullptr);
The member functions work too:
auto weak = original->get_weak_ptr();
auto strong = weak->lock();
const-ness propagates: a strong pointer to const yields a weak pointer to
const and vice versa.
Member types¶
-
using strong_ptr = refcnt_ptr<strong_value_type>¶
-
using const_strong_ptr = refcnt_ptr<const strong_value_type>¶
Methods¶
Unless noted otherwise, all methods are noexcept. The copy and move
constructors and assignment operators are deleted. The destructor is
protected.
-
constexpr weak_reference(intptr_t initial_strong, Owner *owner) noexcept¶
Protected.
initial_strongis the owner’s reference count at the moment the control block is created (it can be any value reached beforehand);owneris a raw pointer to theOwner.
-
void destroy() const¶
Protected. Unlike the rest of this class it is not
noexcept. Called when this control block’s own count reaches 0; the default callsdeleteon the derived pointer. Overridable.
-
void add_ref() const noexcept¶
Increment this control block’s own reference count. Overridable.
-
void sub_ref() const noexcept¶
Decrement this control block’s own count and destroy it at 0. The
Owneralways holds a reference to its control block, so the block outlives the owner. Overridable.
-
const_strong_ptr lock() const noexcept¶
-
strong_ptr lock() noexcept¶
Obtain a strong reference to the
Owner, or a null pointer if it no longer exists.
-
void add_owner_ref() noexcept¶
-
void sub_owner_ref() noexcept¶
Protected. Manage the
Owner’s reference count. Overridable.
-
strong_value_type *lock_owner() const noexcept¶
Protected. Performs the actual lock, returning the owner with its count incremented, or null. Overridable.
-
void on_owner_destruction() const noexcept¶
Protected. A no-op customization point invoked after the
Owneris destroyed (when its strong count hits 0). You cannot access or resurrect the owner from it.
Class isptr::ref_counted_adapter¶
-
template<class T, ref_counted_flags Flags = ref_counted_flags::none, class CountType = default_count_type<Flags>>
class ref_counted_adapter¶ Publicly derives from a non-reference-counted class
Tand fromref_counted. The trailing template parameters are forwarded toref_counted.Aliases
weak_ref_counted_adapter,ref_counted_adapter_standweak_ref_counted_adapter_stmirror theref_countedfamily.-
template<class ...Args>
ref_counted_adapter(Args&&... args)¶ Perfectly forwards to
T’s constructor;noexceptif that constructor is.
-
~ref_counted_adapter() noexcept¶
Protected.
-
template<class ...Args>
Class isptr::ref_counted_wrapper¶
-
template<class T, ref_counted_flags Flags = ref_counted_flags::none, class CountType = default_count_type<Flags>>
class ref_counted_wrapper¶ Stores a member of class
Tand derives fromref_counted. The trailing template parameters are forwarded toref_counted.Aliases
weak_ref_counted_wrapper,ref_counted_wrapper_standweak_ref_counted_wrapper_stmirror theref_countedfamily.-
template<class ...Args>
ref_counted_wrapper(Args&&... args)¶ Perfectly forwards to
wrapped’s constructor;noexceptifT’s constructor is.
-
~ref_counted_wrapper() noexcept¶
Protected.
-
template<class ...Args>