SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
RefPtr.hpp
Go to the documentation of this file.
1#ifndef _REF_PTR_
2#define _REF_PTR_
3
4#include <atomic>
5#include <type_traits>
6#include "SmartPointer.hpp"
7
8namespace Sleak {
9
10/// Reference count shared by every RefPtr aimed at one object.
11///
12/// Allocated separately from the object, and non-templated so that a
13/// RefPtr<Base> converted from a RefPtr<Derived> shares the same count.
14/// The counter is atomic, so copying and destroying RefPtrs across threads
15/// is safe; the pointed-to object still needs its own synchronization.
16/// @see RefPtr
17/// @ingroup memory
19 /// Number of RefPtr instances currently owning the object.
20 std::atomic<size_t> refCount;
22};
23
24/// Atomic, intrusive-refcount smart pointer for engine resources. This is
25/// the standard owning pointer in the engine, used instead of shared_ptr.
26///
27/// Construct one from a raw pointer and it takes ownership, deleting the
28/// object when the last RefPtr to it goes away. Copies share the count;
29/// moves transfer it. Use this wherever the public API asks for an owning
30/// pointer, notably Material and the GPU buffer handles on MeshHandle.
31///
32/// The constructor is explicit, so ownership transfer is always visible at
33/// the call site. Converting RefPtr<Derived> to RefPtr<Base> is allowed
34/// and keeps the same control block. `use_count()` reports the current
35/// reference count.
36///
37/// The reference count is thread-safe. The object it guards is not: two
38/// threads calling into the same pointed-to object still need their own
39/// synchronization. Note also that `get()` on the SmartPointer base throws
40/// NullPointerException when the pointer is null, so test with
41/// `IsValid()` or the bool conversion before dereferencing an optional
42/// resource.
43///
44/// @code{.cpp}
45/// // Take ownership of a freshly created material
46/// auto* raw = new Sleak::Material();
47/// raw->SetRoughness(0.35f);
48/// Sleak::RefPtr<Sleak::Material> material(raw);
49///
50/// // Share it across several objects; each copy bumps the count
51/// crate->AddComponent<Sleak::MaterialComponent>(material);
52/// barrel->AddComponent<Sleak::MaterialComponent>(material);
53///
54/// if (material.IsValid()) {
55/// material->SetMetallic(0.0f); // operator-> reaches the object
56/// }
57/// @endcode
58///
59/// @see SharedControlBlock, SmartPointer, ObjectPtr, WeakPtr
60/// @ingroup memory
61template <typename T>
62class RefPtr : public SmartPointer<T> {
63 // Allow other RefPtr instantiations to access getControlBlock().
64 template <typename U>
65 friend class RefPtr;
66
67protected:
68 SharedControlBlock* controlBlock; // Shared across all types.
69
70
71 public:
72
73 /// Drops one reference, deleting the object and control block at zero.
74 void release() {
75 if (controlBlock && --controlBlock->refCount == 0) {
76 delete this->ptr;
77 delete controlBlock;
78 }
79 }
80 // Constructor
81 explicit RefPtr(T* p = nullptr)
82 : SmartPointer<T>(p), controlBlock(p ? new SharedControlBlock() : nullptr) {}
83
84 // Destructor
86
87 // Copy constructor
88 RefPtr(const RefPtr& other)
89 : SmartPointer<T>(other.ptr), controlBlock(other.controlBlock) {
90 if (controlBlock) {
91 controlBlock->refCount++;
92 }
93 }
94
95 // Copy assignment
96 RefPtr& operator=(const RefPtr& other) {
97 if (this != &other) {
98 release();
99 this->ptr = other.ptr;
101 if (controlBlock) {
102 controlBlock->refCount++;
103 }
104 }
105 return *this;
106 }
107
108 // Move constructor
109 RefPtr(RefPtr&& other) noexcept
110 : SmartPointer<T>(other.ptr), controlBlock(other.controlBlock) {
111 other.ptr = nullptr;
112 other.controlBlock = nullptr;
113 }
114
115 // Move assignment
116 RefPtr& operator=(RefPtr&& other) noexcept {
117 if (this != &other) {
118 release();
119 this->ptr = other.ptr;
120 controlBlock = other.controlBlock;
121 other.ptr = nullptr;
122 other.controlBlock = nullptr;
123 }
124 return *this;
125 }
126
127 // Upcasting constructor: allow constructing RefPtr<Base> from RefPtr<Derived>
128 template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
129 RefPtr(const RefPtr<U>& other)
130 : SmartPointer<T>(other.get()), controlBlock(other.getControlBlock()) {
131 if (controlBlock) controlBlock->refCount++;
132 }
133
134 // Upcasting assignment operator
135 template <typename U>
136 RefPtr& operator=(const RefPtr<U>& other) {
137 static_assert(std::is_base_of<T, U>::value, "T must be a base class of U");
138 if (this != reinterpret_cast<const RefPtr*>(&other)) {
139 release();
140 this->ptr = other.get();
142 if (controlBlock) {
143 controlBlock->refCount++;
144 }
145 }
146 return *this;
147 }
148
149 // Assign nullptr
150 RefPtr& operator=(std::nullptr_t) noexcept {
151 release();
152 this->ptr = nullptr;
153 controlBlock = nullptr;
154 return *this;
155 }
156
157 // Reset the pointer
158 void reset(T* newPtr = nullptr) override {
159 release();
160 this->ptr = newPtr;
161 controlBlock = newPtr ? new SharedControlBlock() : nullptr;
162 }
163
164 // Get the reference count
165 size_t use_count() const {
166 return controlBlock ? controlBlock->refCount.load() : 0;
167 }
168
169 // Provide access to the raw pointer.
170 T* get() const { return this->ptr; }
171
172protected:
173 // Provide access to the shared control block.
175};
176
177} // namespace Sleak
178
179#endif // _REF_PTR_
RefPtr(RefPtr &&other) noexcept
Definition RefPtr.hpp:109
size_t use_count() const
Definition RefPtr.hpp:165
friend class RefPtr
Definition RefPtr.hpp:65
RefPtr & operator=(std::nullptr_t) noexcept
Definition RefPtr.hpp:150
RefPtr(const RefPtr< U > &other)
Definition RefPtr.hpp:129
RefPtr & operator=(RefPtr &&other) noexcept
Definition RefPtr.hpp:116
SharedControlBlock * controlBlock
Definition RefPtr.hpp:68
RefPtr(const RefPtr &other)
Definition RefPtr.hpp:88
T * get() const
Definition RefPtr.hpp:170
void reset(T *newPtr=nullptr) override
Definition RefPtr.hpp:158
RefPtr(T *p=nullptr)
Definition RefPtr.hpp:81
RefPtr & operator=(const RefPtr< U > &other)
Definition RefPtr.hpp:136
RefPtr & operator=(const RefPtr &other)
Definition RefPtr.hpp:96
SharedControlBlock * getControlBlock() const
Definition RefPtr.hpp:174
void release()
Drops one reference, deleting the object and control block at zero.
Definition RefPtr.hpp:74
SmartPointer(T *p=nullptr)
Root namespace for everything the engine exposes.
Definition Camera.hpp:10
std::atomic< size_t > refCount
Number of RefPtr instances currently owning the object.
Definition RefPtr.hpp:20