DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
SmartPointer.h
Go to the documentation of this file.
1
3
4#pragma once
5
6#include "Common.h"
8#include <type_traits>
9#include <utility>
10
11#if defined(_WIN32)
12#ifndef _INTERLOCKED_DECLARED_
13#define _INTERLOCKED_DECLARED_
14extern "C" long __cdecl _InterlockedIncrement(long volatile* Addend);
15extern "C" long __cdecl _InterlockedDecrement(long volatile* Addend);
16#pragma intrinsic(_InterlockedIncrement)
17#pragma intrinsic(_InterlockedDecrement)
18#endif
19#endif
20
21namespace DotNetDupe {
22 namespace System {
23 namespace Internal {
24 inline long AtomicIncrement(volatile long* pLocation) {
25#if defined(_WIN32)
26 return _InterlockedIncrement(pLocation);
27#else
28 return __sync_add_and_fetch(pLocation, 1);
29#endif
30 }
31
32 inline long AtomicDecrement(volatile long* pLocation) {
33#if defined(_WIN32)
34 return _InterlockedDecrement(pLocation);
35#else
36 return __sync_sub_and_fetch(pLocation, 1);
37#endif
38 }
39 }
40
41 // Helper trait to check if a type is complete at compile time
42 template <typename T, typename = void>
43 struct IsComplete : std::false_type {};
44
45 template <typename T>
46 struct IsComplete<T, std::void_t<decltype(sizeof(T))>> : std::true_type {};
47
49 protected:
50 constexpr EnableSharedFromThisBase() noexcept : m_pnRefCount(nullptr) {}
53 virtual ~EnableSharedFromThisBase() = default;
54
55 public:
56 mutable volatile long* m_pnRefCount{nullptr};
57 };
58
59 template <typename T>
60 class EnableSharedFromThis;
61
71 template <typename T>
73 template <typename U>
74 friend class SmartPointer;
75 template <typename U>
77 public:
78 // --- Auto-Allocating Constructors ---
79
86 if constexpr (IsComplete<T>::value) {
87 if constexpr (!std::is_abstract_v<T> && std::is_default_constructible_v<T>) {
88 m_pObject = new T();
89 m_pnRefCount = nullptr;
90 } else {
91 m_pObject = nullptr;
92 m_pnRefCount = nullptr;
93 }
94 } else {
95 m_pObject = nullptr;
96 m_pnRefCount = nullptr;
97 }
98 }
99
105 explicit SmartPointer(bool bIsShared) {
106 if constexpr (IsComplete<T>::value) {
107 if constexpr (!std::is_abstract_v<T> && std::is_default_constructible_v<T>) {
108 m_pObject = new T();
109 m_pnRefCount = bIsShared ? new long(1) : nullptr;
110 SetupEnableSharedFromThis(m_pObject);
111 } else {
112 m_pObject = nullptr;
113 m_pnRefCount = nullptr;
114 }
115 } else {
116 m_pObject = nullptr;
117 m_pnRefCount = nullptr;
118 }
119 }
120
121 // --- Raw Pointer / Explicit Constructors ---
122
127 explicit SmartPointer(T* pPtr) : m_pObject(pPtr), m_pnRefCount(nullptr) {}
128
134 SmartPointer(T* pPtr, bool bIsShared)
135 : m_pObject(pPtr),
136 m_pnRefCount((bIsShared && pPtr != nullptr) ? new long(1) : nullptr) {
137 SetupEnableSharedFromThis(m_pObject);
138 }
139
143 SmartPointer(std::nullptr_t) : m_pObject(nullptr), m_pnRefCount(nullptr) {}
144
149 InternalCleanup();
150 }
151
152 // --- Copy Semantics ---
153
158 SmartPointer(const SmartPointer& objOther) : m_pObject(nullptr), m_pnRefCount(nullptr) {
159 if (objOther.m_pnRefCount == nullptr && objOther.m_pObject != nullptr) {
160 throw SystemException("Cannot copy a Unique SmartPointer. Use Move semantics or initialize as Shared.");
161 }
162 m_pObject = objOther.m_pObject;
163 m_pnRefCount = objOther.m_pnRefCount;
164 if (m_pnRefCount != nullptr) {
165 Internal::AtomicIncrement(m_pnRefCount);
166 }
167 }
168
169 template <typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
170 SmartPointer(const SmartPointer<U>& objOther) : m_pObject(objOther.m_pObject), m_pnRefCount(objOther.m_pnRefCount) {
171 if (objOther.m_pnRefCount == nullptr && objOther.m_pObject != nullptr) {
172 throw SystemException("Cannot copy a Unique SmartPointer. Use Move semantics or initialize as Shared.");
173 }
174 m_pObject = objOther.m_pObject;
175 m_pnRefCount = objOther.m_pnRefCount;
176 if (m_pnRefCount != nullptr) {
177 Internal::AtomicIncrement(m_pnRefCount);
178 }
179 }
180
185 if (this != &objOther) {
186 if (objOther.m_pnRefCount == nullptr && objOther.m_pObject != nullptr) {
187 throw SystemException("Cannot copy a Unique SmartPointer.");
188 }
189 InternalCleanup();
190 m_pObject = objOther.m_pObject;
191 m_pnRefCount = objOther.m_pnRefCount;
192 if (m_pnRefCount != nullptr) {
193 Internal::AtomicIncrement(m_pnRefCount);
194 }
195 }
196 return *this;
197 }
198
199 template <typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
201 if (objOther.m_pnRefCount == nullptr && objOther.m_pObject != nullptr) {
202 throw SystemException("Cannot copy a Unique SmartPointer.");
203 }
204 InternalCleanup();
205 m_pObject = objOther.m_pObject;
206 m_pnRefCount = objOther.m_pnRefCount;
207 if (m_pnRefCount != nullptr) {
208 Internal::AtomicIncrement(m_pnRefCount);
209 }
210 return *this;
211 }
212
213 // --- Move Semantics ---
214
218 SmartPointer(SmartPointer&& objOther) noexcept
219 : m_pObject(objOther.m_pObject), m_pnRefCount(objOther.m_pnRefCount) {
220 objOther.m_pObject = nullptr;
221 objOther.m_pnRefCount = nullptr;
222 }
223
224 template <typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
225 SmartPointer(SmartPointer<U>&& objOther) noexcept
226 : m_pObject(objOther.m_pObject), m_pnRefCount(objOther.m_pnRefCount) {
227 objOther.m_pObject = nullptr;
228 objOther.m_pnRefCount = nullptr;
229 }
230
234 SmartPointer& operator=(SmartPointer&& objOther) noexcept {
235 if (this != &objOther) {
236 InternalCleanup();
237 m_pObject = objOther.m_pObject;
238 m_pnRefCount = objOther.m_pnRefCount;
239 objOther.m_pObject = nullptr;
240 objOther.m_pnRefCount = nullptr;
241 }
242 return *this;
243 }
244
245 template <typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
246 SmartPointer& operator=(SmartPointer<U>&& objOther) noexcept {
247 if (static_cast<const void*>(this) != static_cast<const void*>(&objOther)) {
248 InternalCleanup();
249 m_pObject = objOther.m_pObject;
250 m_pnRefCount = objOther.m_pnRefCount;
251 objOther.m_pObject = nullptr;
252 objOther.m_pnRefCount = nullptr;
253 }
254 return *this;
255 }
256
257 // --- Factory Methods ---
258
263 return SmartPointer<T>(new T(), false);
264 }
265
269 template <typename Arg1, typename... Args>
270 static SmartPointer<T> NewUnique(Arg1&& arg1, Args&&... args) {
271 return SmartPointer<T>(new T(std::forward<Arg1>(arg1), std::forward<Args>(args)...), false);
272 }
273
278 return SmartPointer<T>(new T(), true);
279 }
280
284 template <typename Arg1, typename... Args>
285 static SmartPointer<T> NewShared(Arg1&& arg1, Args&&... args) {
286 return SmartPointer<T>(new T(std::forward<Arg1>(arg1), std::forward<Args>(args)...), true);
287 }
288
289 // --- Static Factory Helpers (C#-like instantiation) ---
290
295 return NewUnique();
296 }
297
301 template <typename Arg1, typename... Args>
302 static SmartPointer<T> New(Arg1&& arg1, Args&&... args) {
303 return NewUnique(std::forward<Arg1>(arg1), std::forward<Args>(args)...);
304 }
305
306 // --- Conversion / Compatibility Aliases ---
307
312 return NewUnique();
313 }
314
318 template <typename Arg1, typename... Args>
319 static SmartPointer<T> MakeUnique(Arg1&& arg1, Args&&... args) {
320 return NewUnique(std::forward<Arg1>(arg1), std::forward<Args>(args)...);
321 }
322
327 return NewShared();
328 }
329
333 template <typename Arg1, typename... Args>
334 static SmartPointer<T> MakeShared(Arg1&& arg1, Args&&... args) {
335 return NewShared(std::forward<Arg1>(arg1), std::forward<Args>(args)...);
336 }
337
338 // --- API Methods ---
339
345 void Attach(T* pPtr, bool bIsShared = false) {
346 Reset(pPtr, bIsShared);
347 }
348
349 // --- Utility Methods ---
350
355 void Reset(T* pPtr = nullptr) {
356 InternalCleanup();
357 m_pObject = pPtr;
358 m_pnRefCount = nullptr;
359 }
360
366 void Reset(T* pPtr, bool bIsShared) {
367 InternalCleanup();
368 m_pObject = pPtr;
369 m_pnRefCount = (bIsShared && pPtr != nullptr) ? new long(1) : nullptr;
370 SetupEnableSharedFromThis(m_pObject);
371 }
372
378 T* Detach() {
379 T* pTemp = m_pObject;
380 m_pnRefCount = nullptr;
381 m_pObject = nullptr;
382 return pTemp;
383 }
384
388 T* Get() const noexcept { return m_pObject; }
389
393 bool IsNull() const noexcept { return m_pObject == nullptr; }
394
398 template <typename U>
400 U* pCast = dynamic_cast<U*>(m_pObject);
401 if (!pCast) return SmartPointer<U>(nullptr);
402 return SmartPointer<U>(pCast, m_pnRefCount);
403 }
404
408 template <typename U>
410 U* pCast = static_cast<U*>(m_pObject);
411 if (!pCast) return SmartPointer<U>(nullptr);
412 return SmartPointer<U>(pCast, m_pnRefCount);
413 }
414
418 template <typename U>
420 U* pCast = const_cast<U*>(m_pObject);
421 if (!pCast) return SmartPointer<U>(nullptr);
422 return SmartPointer<U>(pCast, m_pnRefCount);
423 }
424
425 template <typename From>
427 return sp.template DynamicCast<T>();
428 }
429
430 template <typename From>
432 return sp.template StaticCast<T>();
433 }
434
435 template <typename From>
437 return sp.template ConstCast<T>();
438 }
439
443 int GetRefCount() const noexcept {
444 return (m_pnRefCount != nullptr) ? static_cast<int>(*m_pnRefCount) : 0;
445 }
446
447 // --- Operators ---
448
449 T& operator*() const { return *m_pObject; }
450 T* operator->() const noexcept { return m_pObject; }
451 explicit operator bool() const noexcept { return m_pObject != nullptr; }
452
453 bool operator==(const SmartPointer& other) const noexcept {
454 return m_pObject == other.m_pObject;
455 }
456
457 bool operator!=(const SmartPointer& other) const noexcept {
458 return m_pObject != other.m_pObject;
459 }
460
461 template <typename U>
462 bool operator==(const SmartPointer<U>& other) const noexcept {
463 return m_pObject == other.Get();
464 }
465
466 template <typename U>
467 bool operator!=(const SmartPointer<U>& other) const noexcept {
468 return m_pObject != other.Get();
469 }
470
471 bool operator==(std::nullptr_t) const noexcept {
472 return m_pObject == nullptr;
473 }
474
475 bool operator!=(std::nullptr_t) const noexcept {
476 return m_pObject != nullptr;
477 }
478
479 friend bool operator==(std::nullptr_t, const SmartPointer& sp) noexcept {
480 return sp.m_pObject == nullptr;
481 }
482
483 friend bool operator!=(std::nullptr_t, const SmartPointer& sp) noexcept {
484 return sp.m_pObject != nullptr;
485 }
486
487 template <typename U>
488 bool operator==(const U* pOther) const noexcept {
489 return m_pObject == pOther;
490 }
491
492 template <typename U>
493 bool operator!=(const U* pOther) const noexcept {
494 return m_pObject != pOther;
495 }
496
497 template <typename U>
498 friend bool operator==(const U* pOther, const SmartPointer& sp) noexcept {
499 return pOther == sp.m_pObject;
500 }
501
502 template <typename U>
503 friend bool operator!=(const U* pOther, const SmartPointer& sp) noexcept {
504 return pOther != sp.m_pObject;
505 }
506
507 private:
508 SmartPointer(T* pPtr, volatile long* pnRefCount)
509 : m_pObject(pPtr), m_pnRefCount(pnRefCount) {
510 if (m_pnRefCount != nullptr) {
511 Internal::AtomicIncrement(m_pnRefCount);
512 }
513 SetupEnableSharedFromThis(m_pObject);
514 }
515
516 template <typename U>
517 void SetupEnableSharedFromThis(U* pPtr) {
518 if constexpr (IsComplete<U>::value) {
519 if (pPtr != nullptr && m_pnRefCount != nullptr) {
520 if constexpr (std::is_base_of_v<EnableSharedFromThisBase, U>) {
521 static_cast<EnableSharedFromThisBase*>(pPtr)->m_pnRefCount = m_pnRefCount;
522 } else if constexpr (std::is_polymorphic_v<U>) {
523 if (auto* pBase = dynamic_cast<EnableSharedFromThisBase*>(pPtr)) {
524 pBase->m_pnRefCount = m_pnRefCount;
525 }
526 }
527 }
528 }
529 }
530
531 void InternalCleanup() {
533 if (m_pnRefCount != nullptr) {
534 if (Internal::AtomicDecrement(m_pnRefCount) == 0) {
535 if (m_pObject != nullptr) delete m_pObject;
536 delete const_cast<long*>(m_pnRefCount);
537 }
538 } else if (m_pObject != nullptr) {
540 delete m_pObject;
541 }
542 m_pObject = nullptr;
543 m_pnRefCount = nullptr;
544 }
545
546 T* m_pObject;
547 volatile long* m_pnRefCount;
548 };
549
550 template <typename T>
552 public:
554 if (m_pnRefCount == nullptr) {
555 throw SystemException("SharedFromThis called on an object that is not managed by a shared SmartPointer.");
556 }
557 return SmartPointer<T>(static_cast<T*>(this), m_pnRefCount);
558 }
559
561 if (m_pnRefCount == nullptr) {
562 throw SystemException("SharedFromThis called on an object that is not managed by a shared SmartPointer.");
563 }
564 return SmartPointer<const T>(static_cast<const T*>(this), m_pnRefCount);
565 }
566
567 protected:
568 constexpr EnableSharedFromThis() noexcept = default;
570 EnableSharedFromThis& operator=(const EnableSharedFromThis&) noexcept { return *this; }
571 virtual ~EnableSharedFromThis() = default;
572 };
573
574 template <typename To, typename From>
576 return sp.template DynamicCast<To>();
577 }
578
579 template <typename To, typename From>
581 return sp.template StaticCast<To>();
582 }
583
584 template <typename To, typename From>
586 return sp.template ConstCast<To>();
587 }
588
589 template <typename To, typename From>
591 return sp.template DynamicCast<To>();
592 }
593
594 template <typename To, typename From>
596 return sp.template StaticCast<To>();
597 }
598 }
599}
Defines common cross-platform macros, export decorators, and fundamental types.
long __cdecl _InterlockedIncrement(long volatile *Addend)
long __cdecl _InterlockedDecrement(long volatile *Addend)
Serves as the base class for system exceptions across the library.
EnableSharedFromThisBase & operator=(const EnableSharedFromThisBase &) noexcept
EnableSharedFromThisBase(const EnableSharedFromThisBase &) noexcept
EnableSharedFromThis & operator=(const EnableSharedFromThis &) noexcept
constexpr EnableSharedFromThis() noexcept=default
SmartPointer< const T > SharedFromThis() const
A unified smart pointer that supports both unique and shared ownership semantics.
static SmartPointer< T > NewShared()
Creates a Shared SmartPointer, default constructing T.
bool operator==(const U *pOther) const noexcept
bool operator==(const SmartPointer< U > &other) const noexcept
SmartPointer(SmartPointer &&objOther) noexcept
Move constructor. Transfers ownership from the source.
SmartPointer(std::nullptr_t)
Explicit null constructor.
T * Detach()
Detaches the managed object and returns it. The SmartPointer will no longer own the object.
static SmartPointer< T > NewUnique()
Creates a Unique SmartPointer, default constructing T.
T * operator->() const noexcept
SmartPointer(const SmartPointer &objOther)
Copy constructor. Only permitted if the source is in Shared mode.
static SmartPointer< T > MakeUnique(Arg1 &&arg1, Args &&... args)
Alias for NewUnique. Provided for compatibility.
bool operator!=(std::nullptr_t) const noexcept
void Reset(TimeProvider *pPtr=nullptr)
static SmartPointer< T > StaticCast(const SmartPointer< From > &sp)
void Reset(T *pPtr, bool bIsShared)
Resets the SmartPointer with a specific ownership mode.
~SmartPointer()
Destructor. Cleans up the managed object based on ownership mode.
friend bool operator!=(const U *pOther, const SmartPointer &sp) noexcept
SmartPointer(bool bIsShared)
Constructor with ownership mode flag. Automatically allocates a new instance of T.
static SmartPointer< T > MakeUnique()
Alias for NewUnique (default construction).
SmartPointer & operator=(SmartPointer< U > &&objOther) noexcept
bool IsNull() const noexcept
Checks if the SmartPointer is null.
T * Get() const noexcept
Gets the raw pointer.
static SmartPointer< T > NewShared(Arg1 &&arg1, Args &&... args)
Creates a Shared SmartPointer, forwarding arguments to T's constructor.
static SmartPointer< T > ConstCast(const SmartPointer< From > &sp)
friend bool operator!=(std::nullptr_t, const SmartPointer &sp) noexcept
SmartPointer< U > ConstCast() const
Const casts the managed pointer to another type U and returns a new SmartPointer sharing ownership.
bool operator==(const SmartPointer &other) const noexcept
int GetRefCount() const noexcept
Gets the current reference count. Returns 0 for Unique or Null pointers.
SmartPointer(SmartPointer< U > &&objOther) noexcept
SmartPointer & operator=(SmartPointer &&objOther) noexcept
Move assignment operator. Transfers ownership from the source.
bool operator!=(const SmartPointer &other) const noexcept
bool operator!=(const U *pOther) const noexcept
friend bool operator==(std::nullptr_t, const SmartPointer &sp) noexcept
static SmartPointer< T > New(Arg1 &&arg1, Args &&... args)
Creates a new SmartPointer with variadic arguments for T's constructor.
SmartPointer(T *pPtr, bool bIsShared)
Constructor that specifies ownership mode for a raw pointer.
void Attach(T *pPtr, bool bIsShared=false)
Attaches a new raw pointer to the SmartPointer.
static SmartPointer< T > New()
Creates a new SmartPointer (default construction).
SmartPointer & operator=(const SmartPointer< U > &objOther)
SmartPointer()
Default constructor. For concrete types: Automatically allocates a new instance of T....
SmartPointer & operator=(const SmartPointer &objOther)
Copy assignment operator. Only permitted if the source is in Shared mode.
SmartPointer< U > DynamicCast() const
Dynamically casts the managed pointer to another type U and returns a new SmartPointer sharing owners...
bool operator==(std::nullptr_t) const noexcept
static SmartPointer< T > MakeShared()
Alias for NewShared (default construction).
static SmartPointer< T > NewUnique(Arg1 &&arg1, Args &&... args)
Creates a Unique SmartPointer, forwarding arguments to T's constructor.
SmartPointer(const SmartPointer< U > &objOther)
bool operator!=(const SmartPointer< U > &other) const noexcept
static SmartPointer< T > MakeShared(Arg1 &&arg1, Args &&... args)
Alias for NewShared. Provided for compatibility.
static SmartPointer< T > DynamicCast(const SmartPointer< From > &sp)
SmartPointer(T *pPtr)
Constructor for explicit raw pointer attachment.
SmartPointer< U > StaticCast() const
Statically casts the managed pointer to another type U and returns a new SmartPointer sharing ownersh...
friend bool operator==(const U *pOther, const SmartPointer &sp) noexcept
SystemException()
Initializes a new instance of the SystemException class with a default message.
Definition Exception.cpp:48
long AtomicIncrement(volatile long *pLocation)
long AtomicDecrement(volatile long *pLocation)
SmartPointer< To > ConstPointerCast(const SmartPointer< From > &sp)
SmartPointer< To > DynamicPointerCast(const SmartPointer< From > &sp)
SmartPointer< To > StaticCast(const SmartPointer< From > &sp)
SmartPointer< To > DynamicCast(const SmartPointer< From > &sp)
SmartPointer< To > StaticPointerCast(const SmartPointer< From > &sp)