Mbed OS Reference
Loading...
Searching...
No Matches
SharedPtr.h
1/* mbed Microcontroller Library
2 * Copyright (c) 2006-2018 ARM Limited
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef __SHAREDPTR_H__
19#define __SHAREDPTR_H__
20
21#include <stdlib.h>
22
23#include <stdint.h>
24#include <stddef.h>
25
26#include "platform/mbed_atomic.h"
27
28namespace mbed {
29
30/** Shared pointer class.
31 *
32 * A shared pointer is a "smart" pointer that retains ownership of an object using
33 * reference counting across all smart pointers referencing that object.
34 *
35 * @code
36 * #include "platform/SharedPtr.h"
37 *
38 * void test() {
39 * struct MyStruct { int a; };
40 *
41 * // Create shared pointer
42 * SharedPtr<MyStruct> ptr( new MyStruct );
43 *
44 * // Increase reference count
45 * SharedPtr<MyStruct> ptr2( ptr );
46 *
47 * ptr = nullptr; // Reference to the struct instance is still held by ptr2
48 *
49 * ptr2 = nullptr; // The raw pointer is freed
50 * }
51 * @endcode
52 *
53 *
54 * It is similar to the std::shared_ptr class introduced in C++11;
55 * however, this is not a compatible implementation (no weak pointer, no make_shared, no custom deleters and so on.)
56 *
57 * Usage: SharedPtr<Class> ptr(new Class())
58 *
59 * When ptr is passed around by value, the copy constructor and
60 * destructor manages the reference count of the raw pointer.
61 * If the counter reaches zero, delete is called on the raw pointer.
62 *
63 * To avoid loops, use "weak" references by calling the original
64 * pointer directly through ptr.get().
65 */
66
67template <class T>
68class SharedPtr {
69public:
70 /**
71 * @brief Create empty SharedPtr not pointing to anything.
72 * @details Used for variable declaration.
73 */
74 constexpr SharedPtr(): _ptr(), _counter()
75 {
76 }
77
78 /**
79 * @brief Create empty SharedPtr not pointing to anything.
80 */
81 constexpr SharedPtr(std::nullptr_t) : SharedPtr()
82 {
83 }
84
85 /**
86 * @brief Create new SharedPtr
87 * @param ptr Pointer to take control over
88 */
89 SharedPtr(T *ptr): _ptr(ptr), _counter()
90 {
91 // Allocate counter on the heap, so it can be shared
92 if (_ptr != nullptr) {
93 _counter = new uint32_t(1);
94 }
95 }
96
97 /**
98 * @brief Destructor.
99 * @details Decrement reference counter, and delete object if no longer pointed to.
100 */
102 {
103 decrement_counter();
104 }
105
106 /**
107 * @brief Copy constructor.
108 * @details Create new SharedPtr from other SharedPtr by
109 * copying pointer to original object and pointer to counter.
110 * @param source Object being copied from.
111 */
112 SharedPtr(const SharedPtr &source): _ptr(source._ptr), _counter(source._counter)
113 {
114 // Increment reference counter
115 if (_ptr != nullptr) {
116 core_util_atomic_incr_u32(_counter, 1);
117 }
118 }
119
120 /**
121 * @brief Move constructor.
122 * @details Create new SharedPtr from other SharedPtr by
123 * moving pointer to original object and pointer to counter.
124 * @param source Object being copied from.
125 */
126 SharedPtr(SharedPtr &&source): _ptr(source._ptr), _counter(source._counter)
127 {
128 source._ptr = nullptr;
129 source._counter = nullptr;
130 }
131
132 /**
133 * @brief Copy assignment operator.
134 * @details Cleanup previous reference and assign new pointer and counter.
135 * @param source Object being assigned from.
136 * @return Object being assigned.
137 */
139 {
140 if (this != &source) {
141 // Clean up by decrementing counter
142 decrement_counter();
143
144 // Assign new values
145 _ptr = source.get();
146 _counter = source.get_counter();
147
148 // Increment new counter
149 if (_ptr != nullptr) {
150 core_util_atomic_incr_u32(_counter, 1);
151 }
152 }
153
154 return *this;
155 }
156
157 /**
158 * @brief Move assignment operator.
159 * @details Cleanup previous reference and assign new pointer and counter.
160 * @param source Object being assigned from.
161 * @return Object being assigned.
162 */
164 {
165 if (this != &source) {
166 // Clean up by decrementing counter
167 decrement_counter();
168
169 // Assign new values
170 _ptr = source._ptr;
171 _counter = source._counter;
172
173 source._ptr = nullptr;
174 source._counter = nullptr;
175 }
176
177 return *this;
178 }
179
180 /**
181 * @brief Replaces the managed pointer with a new unmanaged pointer.
182 * @param[in] ptr the new raw pointer to manage.
183 */
184 void reset(T *ptr)
185 {
186 // Clean up by decrementing counter
187 decrement_counter();
188
189 _ptr = ptr;
190 if (ptr != nullptr) {
191 // Allocate counter on the heap, so it can be shared
192 _counter = new uint32_t(1);
193 } else {
194 _counter = nullptr;
195 }
196 }
197
198 /**
199 * @brief Replace the managed pointer with a null pointer.
200 */
201 void reset()
202 {
203 // Clean up by decrementing counter
204 decrement_counter();
205
206 _ptr = nullptr;
207 _counter = nullptr;
208 }
209
210 /**
211 * @brief Raw pointer accessor.
212 * @details Get raw pointer to object pointed to.
213 * @return Pointer.
214 */
215 T *get() const
216 {
217 return _ptr;
218 }
219
220 /**
221 * @brief Reference count accessor.
222 * @return Reference count.
223 */
224 uint32_t use_count() const
225 {
226 if (_ptr != nullptr) {
227 return core_util_atomic_load_u32(_counter);
228 } else {
229 return 0;
230 }
231 }
232
233 /**
234 * @brief Dereference object operator.
235 * @details Override to return the object pointed to.
236 */
237 T &operator*() const
238 {
239 return *_ptr;
240 }
241
242 /**
243 * @brief Dereference object member operator.
244 * @details Override to return return member in object pointed to.
245 */
246 T *operator->() const
247 {
248 return _ptr;
249 }
250
251 /**
252 * @brief Boolean conversion operator.
253 * @return Whether or not the pointer is null.
254 */
255 operator bool() const
256 {
257 return _ptr != nullptr;
258 }
259
260private:
261 /**
262 * @brief Get pointer to reference counter.
263 * @return Pointer to reference counter.
264 */
265 uint32_t *get_counter() const
266 {
267 return _counter;
268 }
269
270 /**
271 * @brief Decrement reference counter.
272 * @details If count reaches zero, free counter and delete object pointed to.
273 * Does not modify our own pointers - assumption is they will be overwritten
274 * or destroyed immediately afterwards.
275 */
276 void decrement_counter()
277 {
278 if (_ptr != nullptr) {
279 if (core_util_atomic_decr_u32(_counter, 1) == 0) {
280 delete _counter;
281 delete _ptr;
282 }
283 }
284 }
285
286private:
287 // Pointer to shared object
288 T *_ptr;
289
290 // Pointer to shared reference counter
291 uint32_t *_counter;
292};
293
294/** Non-member relational operators.
295 */
296template <class T, class U>
297bool operator== (const SharedPtr<T> &lhs, const SharedPtr<U> &rhs)
298{
299 return (lhs.get() == rhs.get());
300}
301
302template <class T, typename U>
303bool operator== (const SharedPtr<T> &lhs, U rhs)
304{
305 return (lhs.get() == (T *) rhs);
306}
307
308template <class T, typename U>
309bool operator== (U lhs, const SharedPtr<T> &rhs)
310{
311 return ((T *) lhs == rhs.get());
312}
313
314/** Non-member relational operators.
315 */
316template <class T, class U>
317bool operator!= (const SharedPtr<T> &lhs, const SharedPtr<U> &rhs)
318{
319 return (lhs.get() != rhs.get());
320}
321
322template <class T, typename U>
323bool operator!= (const SharedPtr<T> &lhs, U rhs)
324{
325 return (lhs.get() != (T *) rhs);
326}
327
328template <class T, typename U>
329bool operator!= (U lhs, const SharedPtr<T> &rhs)
330{
331 return ((T *) lhs != rhs.get());
332}
333
334} /* namespace mbed */
335
336#ifndef MBED_NO_GLOBAL_USING_DIRECTIVE
337using mbed::SharedPtr;
338#endif
339
340#endif // __SHAREDPTR_H__
Shared pointer class.
Definition: SharedPtr.h:68
SharedPtr operator=(SharedPtr &&source)
Move assignment operator.
Definition: SharedPtr.h:163
~SharedPtr()
Destructor.
Definition: SharedPtr.h:101
T & operator*() const
Dereference object operator.
Definition: SharedPtr.h:237
void reset(T *ptr)
Replaces the managed pointer with a new unmanaged pointer.
Definition: SharedPtr.h:184
constexpr SharedPtr(std::nullptr_t)
Create empty SharedPtr not pointing to anything.
Definition: SharedPtr.h:81
T * operator->() const
Dereference object member operator.
Definition: SharedPtr.h:246
SharedPtr(SharedPtr &&source)
Move constructor.
Definition: SharedPtr.h:126
constexpr SharedPtr()
Create empty SharedPtr not pointing to anything.
Definition: SharedPtr.h:74
void reset()
Replace the managed pointer with a null pointer.
Definition: SharedPtr.h:201
SharedPtr(const SharedPtr &source)
Copy constructor.
Definition: SharedPtr.h:112
T * get() const
Raw pointer accessor.
Definition: SharedPtr.h:215
uint32_t use_count() const
Reference count accessor.
Definition: SharedPtr.h:224
SharedPtr operator=(const SharedPtr &source)
Copy assignment operator.
Definition: SharedPtr.h:138
SharedPtr(T *ptr)
Create new SharedPtr.
Definition: SharedPtr.h:89
uint32_t core_util_atomic_incr_u32(volatile uint32_t *valuePtr, uint32_t delta)
Atomic increment.
uint32_t core_util_atomic_decr_u32(volatile uint32_t *valuePtr, uint32_t delta)
Atomic decrement.