IRC_SERVER
By @hyunjunk (hyunjun2372@gmail.com)
Loading...
Searching...
No Matches
SharedPtr.hpp
Go to the documentation of this file.
1#pragma once
2
3// DEBUG
4#include <typeinfo>
5
6#include "Core/Log.hpp"
11
12
13namespace IRCCore
14{
15
16namespace detail
17{
18/** Do not use this class directly. Use MakeShared function.
19 *
20 * @details We will use placement new/delete
21 * The ControlBlock should not be deleted even after data's destructor is called.
22 * ControlBlock is deleted when both StrongRefCount and WeakRefCount are become 0.
23 *
24 * @warning "Never" change the order of the data[sizeof(T)] member.
25 * This feature is implemented using the c++ standard that
26 * the address of the first member in structure is same as the address of the structure itself.
27 * (see MakeShared() implementation)
28 * */
29template <typename T>
30struct ControlBlock : public FlexibleMemoryPoolingBase< ControlBlock< T > >
31{
32 ALIGNAS(ALIGNOF(T)) char data[sizeof(T)];
33
37
38 /** <T> reference of data for debugging watch */
40
43 , WeakRefCount(0)
44 , bExpired(false)
45 , _Data(reinterpret_cast<T&>(data))
46 {
47 }
48
50 {
51 }
52};
53
54} // namespace detail
55
56
57
58template <typename T>
59class SharedPtr;
60
61template <typename T>
62class WeakPtr;
63
64/** @name MakeSharedGroup
65 * @anchor MakeSharedGroup
66 *
67 * @details
68 * @brief Function to create a shared pointer with a new object.
69 *
70 * @param T Type of the object to be created. (Not support Array type. e.g. int[], char[])
71 * @param ... Arguments to be passed to the constructor of the object. (up to 4 arguments)
72 *
73 * @return A new shared pointer to the object.
74 *
75 * @details Support only up to 4 arguments because variadic template is not available in c++98.
76 * Example usage:
77 * @code
78 * SharedPtr<int> A = MakeShared<int>(5);
79 * @endcode
80 *
81 * @ref SharedPtr
82 */
83///@{
84/** @copydetails MakeSharedGroup */
85template <typename T>
87{
89 new (&controlBlock->data) T();
90 return SharedPtr<T>(controlBlock);
91}
92
93template <typename T, typename A1>
95{
97 new (&controlBlock->data) T(a1);
98 return SharedPtr<T>(controlBlock);
99}
100
101template <typename T, typename A1, typename A2>
103{
105 new (&controlBlock->data) T(a1, a2);
106 return SharedPtr<T>(controlBlock);
107}
108
109template <typename T, typename A1, typename A2, typename A3>
111{
113 new (&controlBlock->data) T(a1, a2, a3);
114 return SharedPtr<T>(controlBlock);
115}
116
117template <typename T, typename A1, typename A2, typename A3, typename A4>
118NODISCARD SharedPtr<T> MakeShared(A1 a1, A2 a2, A3 a3, A4 a4)
119{
121 new (&controlBlock->data) T(a1, a2, a3, a4);
122 return SharedPtr<T>(controlBlock);
123}
124///@}
125
126/** Shared pointer custom implementation for C++98 standard
127 *
128 * @details Example usage:
129 * @code
130 * SharedPtr<int> A(new int(5)); //< Create a new resource using MakeShared function
131 * {
132 * SharedPtr<int> B = A;
133 * WeakPtr<int> C = B;
134 *
135 * std::cout << *A.get() << std::endl; //< 5
136 * std::cout << *B.get() << std::endl; //< 5
137 *
138 * if (C.expired())
139 * {
140 * std::cout << "C is expired" << std::endl;
141 * }
142 * else
143 * {
144 * // Lock the weak pointer to access the resource.
145 * // If the C is expired while executing the lock() method, the locked_C.get() will be NULL.
146 * SharedPtr<int> locked_C = C.lock();
147 * std::cout << *locked_C.get() << std::endl; //< 5
148 *
149 * } //< The locked_C will be released after the scope ends.
150 *
151 * A.reset(); //< Release the resource
152 *
153 * } //< B will be release and resource will be deallocated.
154 * @endcode
155 *
156 * @see MakeSharedGroup
157 *
158 * @tparam T Type of the object to be managed by the shared pointer. (Not support Array type. e.g. int[], char[])
159 *
160 * @warning Not thread-safe
161 */
162template <typename T>
164{
165 friend class WeakPtr<T>;
166
167public:
168 inline SharedPtr()
169 : mControlBlock(NULL)
170 {
171 }
172
173 inline SharedPtr(T* ptr)
174 : mControlBlock(NULL)
175 {
176 if (ptr != NULL)
177 {
179 mControlBlock->StrongRefCount = 1;
180 new (&mControlBlock->data) T(*ptr);
181 }
182 }
183
186 {
187 if (&rhs == this)
188 {
189 return;
190 }
191
192 if (mControlBlock != NULL)
193 {
194 mControlBlock->StrongRefCount += 1;
195 }
196 }
197
198 /** Create a shared pointer from the control block.
199 *
200 * @warning Don't use without a knowledge of the internal implementation.
201 * @see SharedPtr::GetControlBlock
202 */
204 : mControlBlock(controlBlock)
205 {
206 Assert(mControlBlock != NULL);
207
208 if (mControlBlock != NULL)
209 {
210 if (mControlBlock->bExpired)
211 {
212 mControlBlock = NULL;
213 }
214 else
215 {
216 mControlBlock->StrongRefCount += 1;
217 }
218 }
219 }
220
222 {
223 this->Reset();
224 }
225
227 {
228 this->Reset();
229
231 if (mControlBlock != NULL)
232 {
233 mControlBlock->StrongRefCount += 1;
234 }
235
236 return *this;
237 }
238
240 {
241 Assert(mControlBlock != NULL);
242 return *reinterpret_cast<T*>(&mControlBlock->data);
243 }
244
246 {
247 Assert(mControlBlock != NULL);
248 return reinterpret_cast<T*>(&mControlBlock->data);
249 }
250
251 FORCEINLINE bool operator==(const SharedPtr<T>& rhs) const
252 {
253 return mControlBlock == rhs.mControlBlock;
254 }
255
256 FORCEINLINE bool operator==(const T* rhs) const
257 {
258 return Get() == rhs;
259 }
260
261 FORCEINLINE bool operator!=(const T* rhs) const
262 {
263 return Get() != rhs;
264 }
265
266 FORCEINLINE bool operator!=(const SharedPtr<T>& rhs) const
267 {
268 return mControlBlock != rhs.mControlBlock;
269 }
270
271 FORCEINLINE T* Get() const
272 {
273 if (mControlBlock != NULL)
274 {
275 return reinterpret_cast<T*>(&mControlBlock->data);
276 }
277 return NULL;
278 }
279
281 {
282 if (mControlBlock != NULL)
283 {
284 Assert(mControlBlock->StrongRefCount > 0);
285
286 if (mControlBlock->StrongRefCount == 1)
287 {
288 mControlBlock->bExpired = true;
289
290 T* ptrData = reinterpret_cast<T*>(&mControlBlock->data);
291 ptrData->~T();
292
293 Assert(mControlBlock->StrongRefCount != 0);
294 if (mControlBlock->WeakRefCount == 0)
295 {
296 delete mControlBlock;
297 }
298 }
299 else
300 {
301 mControlBlock->StrongRefCount -= 1;
302 }
303 }
304
305 mControlBlock = NULL;
306 }
307
308 FORCEINLINE size_t UseCount() const
309 {
310 if (mControlBlock != NULL)
311 {
312 return mControlBlock->StrongRefCount;
313 }
314 return 0;
315 }
316
318 {
321 rhs.mControlBlock = temp;
322 }
323
324 /** Get the control block of the shared pointer.
325 *
326 * @attention
327 * Don't use without a knowledge of the internal implementation.
328 *
329 * @details
330 * ## [한국어]
331 * SharedPtr는 SharedPtr이나 WeakPtr 서로에 대한 복사만 가능하다.
332 * SharedPtr::Get() 등을 통해 직접적으로 데이터의 포인터를 얻은 뒤 해당 주소로 SharedPtr을 생성한다면
333 * 기존과 같은 데이터를 공유하는 것이 아닌 완전히 새로운 데이터와 ControlBlock를 생성하게 된다.
334 *
335 * 하지만, 데이터의 주소가 아닌 ControlBlock의 주소를 얻은 뒤 이를 통해 SharedPtr을 생성한다면
336 * 기존의 데이터와 ControlBlock을 공유할 수 있다.
337 * 특수한 경우에만 사용해야 하며, ControlBlock의 주소를 얻고 이를 통해 SharedPtr을 생성할 때 까지
338 * 해당 ControlBlock이 삭제되지 않도록 주의해야 한다.
339 */
344
345private:
347};
348
349} // namespace IRCCore
#define FORCEINLINE
Definition AttributeDefines.hpp:55
#define NODISCARD
Definition AttributeDefines.hpp:17
#define Assert(exp)
Implemented as direct interrupt to avoid dirtying the call stack with assert function when debugging.
Definition MacroDefines.hpp:30
Base class for memory pooling with new/delete operator overloading.
Definition FlexibleMemoryPoolingBase.hpp:39
Shared pointer custom implementation for C++98 standard.
Definition SharedPtr.hpp:164
detail::ControlBlock< T > * mControlBlock
Definition SharedPtr.hpp:346
T * Get() const
Definition SharedPtr.hpp:271
SharedPtr(const SharedPtr< T > &rhs)
Definition SharedPtr.hpp:184
SharedPtr< T > & operator=(const SharedPtr< T > &rhs)
Definition SharedPtr.hpp:226
SharedPtr()
Definition SharedPtr.hpp:168
bool operator==(const T *rhs) const
Definition SharedPtr.hpp:256
detail::ControlBlock< T > * GetControlBlock() const
Get the control block of the shared pointer.
Definition SharedPtr.hpp:340
SharedPtr(detail::ControlBlock< T > *controlBlock)
Create a shared pointer from the control block.
Definition SharedPtr.hpp:203
bool operator!=(const T *rhs) const
Definition SharedPtr.hpp:261
T * operator->() const
Definition SharedPtr.hpp:245
~SharedPtr()
Definition SharedPtr.hpp:221
size_t UseCount() const
Definition SharedPtr.hpp:308
bool operator!=(const SharedPtr< T > &rhs) const
Definition SharedPtr.hpp:266
T & operator*() const
Definition SharedPtr.hpp:239
void Reset()
Definition SharedPtr.hpp:280
SharedPtr(T *ptr)
Definition SharedPtr.hpp:173
bool operator==(const SharedPtr< T > &rhs) const
Definition SharedPtr.hpp:251
void Swap(SharedPtr< T > &rhs)
Definition SharedPtr.hpp:317
Weak pointer custom implementation for C++98 standard.
Definition WeakPtr.hpp:18
Definition ControlBlock.hpp:7
SharedPtr< T > MakeShared()
Definition SharedPtr.hpp:86
Do not use this class directly.
Definition SharedPtr.hpp:31
~ControlBlock()
Definition SharedPtr.hpp:49
size_t WeakRefCount
Definition SharedPtr.hpp:35
bool bExpired
Definition SharedPtr.hpp:36
ControlBlock()
Definition SharedPtr.hpp:41
T & _Data
<T> reference of data for debugging watch
Definition SharedPtr.hpp:39
size_t StrongRefCount
Definition SharedPtr.hpp:34
ALIGNAS(ALIGNOF(T)) char data[sizeof(T)]