1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
#ifndef KSTD_BITS_SHARED_PTR_HPP
#define KSTD_BITS_SHARED_PTR_HPP
#include <atomic>
namespace kstd
{
/**
* @brief Shared_pointer is a smart pointer that retains shared ownership of an object through a pointer. Several
* shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of
* the following happens: the last remaining shared_ptr owning the object is destroyed; the last remaining
* shared_ptr owning the object is assigned another pointer via operator= or reset(). A
* shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used
* to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(),
* the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count
* reaches zero.
*
* @tparam T The type of the managed object.
*/
template<typename T>
struct shared_ptr
{
/**
* @brief Constructor.
*
* @param pointer A pointer to an object to manage (default is nullptr).
*/
[[gnu::section(".stl_text")]]
explicit shared_ptr(T * pointer = nullptr)
: pointer(pointer)
, ref_count(new std::atomic<std::size_t>(pointer != nullptr ? 1 : 0))
{
// Nothing to do.
}
/**
* @brief Copy constructor.
*
* @param other The shared_ptr to copy from.
*/
[[gnu::section(".stl_text")]]
shared_ptr(shared_ptr const & other)
: pointer(other.pointer)
, ref_count(other.ref_count)
{
if (pointer != nullptr)
{
++(*ref_count);
}
}
/**
* @brief Move constructor.
*
* @param other The shared_ptr to move from.
*/
[[gnu::section(".stl_text")]]
shared_ptr(shared_ptr && other) noexcept
: pointer(other.pointer)
, ref_count(other.ref_count)
{
other.pointer = nullptr;
other.ref_count = nullptr;
}
/**
* @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the
* object managed by r. If r manages no object, *this manages no object too. Equivalent to
* shared_ptr<T>(r).swap(*this).
*
* @param other Another smart pointer to share the ownership with.
* @return Reference to this shared pointer.
*/
[[gnu::section(".stl_text")]]
shared_ptr & operator=(shared_ptr const & other)
{
if (this != &other)
{
cleanup();
pointer = other.pointer;
ref_count = other.ref_count;
if (pointer != nullptr)
{
++(*ref_count);
}
}
return *this;
}
/**
* @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of
* the previous state of r, and r is empty. Equivalent to shared_ptr<T>(std::move(r)).swap(*this).
*
* @param other Another smart pointer to acquire the ownership from.
* @return Reference to this shared pointer.
*/
[[gnu::section(".stl_text")]]
shared_ptr & operator=(shared_ptr && other) noexcept
{
if (this != &other)
{
cleanup();
pointer = other.pointer;
ref_count = other.ref_count;
other.pointer = nullptr;
other.ref_count = nullptr;
}
return *this;
}
/**
* @brief Destructor. Cleans up resources if necessary.
*/
[[gnu::section(".stl_text")]]
~shared_ptr()
{
cleanup();
}
/**
* @brief Replaces the managed object.
*
* @param ptr Pointer to a new object to manage (default = nullptr).
*/
[[gnu::section(".stl_text")]]
void reset(T * ptr = nullptr)
{
cleanup();
pointer = ptr;
ref_count = new std::atomic<std::size_t>(ptr != nullptr ? 1 : 0);
}
/**
* @brief Exchanges the stored pointer values and the ownerships of *this and r. Reference counts, if any, are not
* adjusted.
*
* @param other The shared_ptr to swap with.
*/
[[gnu::section(".stl_text")]]
void swap(shared_ptr & other)
{
std::swap(pointer, other.pointer);
std::swap(ref_count, other.ref_count);
}
/**
* @brief Dereference operator. If get() is a null pointer, the behavior is undefined.
*
* @return Returns the object owned by *this, equivalent to *get().
*/
[[gnu::section(".stl_text")]]
auto operator*() const -> T &
{
return *pointer;
}
/**
* @brief Member access operator.
*
* @return Returns a pointer to the object owned by *this, i.e. get().
*/
[[gnu::section(".stl_text")]]
auto operator->() const -> T *
{
return pointer;
}
/**
* @brief Returns a pointer to the managed object or nullptr if no object is owned.
*
* @return Pointer to the managed object or nullptr if no object is owned.
*/
[[gnu::section(".stl_text")]]
auto get() const -> T *
{
return pointer;
}
/**
* @brief Returns the number of different shared_ptr instances (*this included) managing the current object. If
* there is no managed object, 0 is returned.
*
* @note Common use cases include comparison with 0. If use_count returns zero, the shared pointer is empty
* and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1,
* there are no other owners.
*
* @return The number of Shared_pointer instances managing the current object or 0 if there is no managed
* object.
*/
[[gnu::section(".stl_text")]]
auto use_count() const -> std::size_t
{
if (pointer != nullptr)
{
return *ref_count;
}
return 0;
}
/**
* @brief Checks whether *this owns an object, i.e. whether get() != nullptr.
*
* @return true if *this owns an object, false otherwise.
*/
[[gnu::section(".stl_text")]]
explicit operator bool() const
{
return pointer != nullptr;
}
/**
* @brief Defaulted three-way comparator operator.
*/
[[gnu::section(".stl_text")]]
auto operator<=>(shared_ptr const & other) const = default;
private:
/**
* @brief Releases ownership and deletes the object if this was the last reference to the owned managed object.
*/
[[gnu::section(".stl_text")]]
auto cleanup() -> void
{
if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0)
{
delete pointer;
delete ref_count;
}
}
T * pointer; ///< The managed object.
std::atomic<std::size_t> * ref_count; ///< Reference count.
};
/**
* @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls
* lhs.swap(rhs).
*
* @tparam T Type of the managed object.
* @param lhs, rhs Smart pointers whose contents to swap.
*/
template<typename T>
auto swap(shared_ptr<T> & lhs, shared_ptr<T> & rhs) -> void
{
lhs.swap(rhs);
}
/**
* @brief Constructs an object of type T and wraps it in a shared_ptr. Constructs a non-array type T. The
* arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is
* not an array type. The function is equivalent to: shared_ptr<T>(new T(std::forward<Args>(args)...)).
*
* @tparam T Type of the managed object.
* @tparam Args Argument types for T's constructor.
* @param args List of arguments with which an instance of T will be constructed.
* @returns Shared_pointer of an instance of type T.
*/
template<typename T, typename... Args>
auto make_shared(Args &&... args) -> shared_ptr<T>
{
return shared_ptr<T>(new T(std::forward<Args>(args)...));
}
} // namespace kstd
#endif
|