SleakEngine
0.1.0
C++23 multi-backend game engine
Toggle main menu visibility
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
8
namespace
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
18
struct
SharedControlBlock
{
19
/// Number of RefPtr instances currently owning the object.
20
std::atomic<size_t>
refCount
;
21
SharedControlBlock
() :
refCount
(1) {}
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
61
template
<
typename
T>
62
class
RefPtr
:
public
SmartPointer
<T> {
63
// Allow other RefPtr instantiations to access getControlBlock().
64
template
<
typename
U>
65
friend
class
RefPtr
;
66
67
protected
:
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
85
~RefPtr
() {
release
(); }
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
;
100
controlBlock
= other.
controlBlock
;
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
();
141
controlBlock
= other.
getControlBlock
();
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
172
protected
:
173
// Provide access to the shared control block.
174
SharedControlBlock
*
getControlBlock
()
const
{
return
controlBlock
; }
175
};
176
177
}
// namespace Sleak
178
179
#endif
// _REF_PTR_
SmartPointer.hpp
Sleak::RefPtr::RefPtr
RefPtr(RefPtr &&other) noexcept
Definition
RefPtr.hpp:109
Sleak::RefPtr::use_count
size_t use_count() const
Definition
RefPtr.hpp:165
Sleak::RefPtr::RefPtr
friend class RefPtr
Definition
RefPtr.hpp:65
Sleak::RefPtr::operator=
RefPtr & operator=(std::nullptr_t) noexcept
Definition
RefPtr.hpp:150
Sleak::RefPtr::RefPtr
RefPtr(const RefPtr< U > &other)
Definition
RefPtr.hpp:129
Sleak::RefPtr::operator=
RefPtr & operator=(RefPtr &&other) noexcept
Definition
RefPtr.hpp:116
Sleak::RefPtr::controlBlock
SharedControlBlock * controlBlock
Definition
RefPtr.hpp:68
Sleak::RefPtr::RefPtr
RefPtr(const RefPtr &other)
Definition
RefPtr.hpp:88
Sleak::RefPtr::get
T * get() const
Definition
RefPtr.hpp:170
Sleak::RefPtr::reset
void reset(T *newPtr=nullptr) override
Definition
RefPtr.hpp:158
Sleak::RefPtr::RefPtr
RefPtr(T *p=nullptr)
Definition
RefPtr.hpp:81
Sleak::RefPtr::operator=
RefPtr & operator=(const RefPtr< U > &other)
Definition
RefPtr.hpp:136
Sleak::RefPtr::operator=
RefPtr & operator=(const RefPtr &other)
Definition
RefPtr.hpp:96
Sleak::RefPtr::getControlBlock
SharedControlBlock * getControlBlock() const
Definition
RefPtr.hpp:174
Sleak::RefPtr::release
void release()
Drops one reference, deleting the object and control block at zero.
Definition
RefPtr.hpp:74
Sleak::RefPtr::~RefPtr
~RefPtr()
Definition
RefPtr.hpp:85
Sleak::SmartPointer::ptr
T * ptr
Definition
SmartPointer.hpp:26
Sleak::SmartPointer::SmartPointer
SmartPointer(T *p=nullptr)
Definition
SmartPointer.hpp:29
Sleak
Root namespace for everything the engine exposes.
Definition
Camera.hpp:10
Sleak::SharedControlBlock
Definition
RefPtr.hpp:18
Sleak::SharedControlBlock::refCount
std::atomic< size_t > refCount
Number of RefPtr instances currently owning the object.
Definition
RefPtr.hpp:20
Sleak::SharedControlBlock::SharedControlBlock
SharedControlBlock()
Definition
RefPtr.hpp:21
include
public
Memory
RefPtr.hpp
Generated on
for SleakEngine by
1.18.0