Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
SharedPtr.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Memory_SharedPtr_h_
5#define _Stroika_Foundation_Memory_SharedPtr_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <atomic>
10#include <compare>
11#include <cstdint>
12#include <type_traits>
13
14#include "Stroika/Foundation/Common/Common.h"
15
16/**
17 * \file
18 */
19_DeprecatedFile_ ("Use shared_ptr instead");
20
21namespace Stroika::Foundation::Memory {
22
23 DISABLE_COMPILER_MSC_WARNING_START (4996);
24 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
25 DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
26
27 struct [[deprecated ("Since Stroika v3, this is deprecated, and will go away - use shared_ptr")]] SharedPtrBase {
28 /**
29 * Note - though we COULD use a smaller reference count type (e.g. uint32_t - for 64bit machines).
30 */
31 using ReferenceCountType = unsigned int;
32 };
33
34 namespace Private_ {
35 // This is used to wrap/combine the shared pointer with the counter.
36 struct ReferenceCounterContainerType_ {
37 atomic<SharedPtrBase::ReferenceCountType> fCount;
38 bool fDeleteCounter_;
39 ReferenceCounterContainerType_ ();
40 ReferenceCounterContainerType_ (const ReferenceCounterContainerType_&) = delete;
41 ReferenceCounterContainerType_ (bool deleteCounter);
42 ReferenceCounterContainerType_& operator= (const ReferenceCounterContainerType_&) = delete;
43 };
44 }
45
46 template <typename T>
47 class [[deprecated ("Since Stroika v3, this is deprecated, and will go away - use shared_ptr")]] enable_shared_from_this;
48
49 namespace Private_ {
50 template <typename T>
51 class Envelope_;
52 }
53
54 template <typename T>
55 class [[deprecated ("Since Stroika v3, this is deprecated, and will go away - use shared_ptr")]] SharedPtr : public SharedPtrBase {
56 public:
57 using element_type = T;
58
59 private:
60 using Envelope_ = Private_::Envelope_<T>;
61
62 public:
63 /**
64 */
65 SharedPtr () noexcept;
66 SharedPtr (nullptr_t) noexcept;
67 template <typename T2, enable_if_t<is_convertible_v<T2*, T*>>* = nullptr>
68 explicit SharedPtr (T2* from);
69 SharedPtr (const SharedPtr& from) noexcept;
70 SharedPtr (SharedPtr&& from) noexcept;
71 template <typename T2, enable_if_t<is_convertible_v<T2*, T*>>* = nullptr>
72 SharedPtr (const SharedPtr<T2>& from) noexcept;
73 template <typename T2, enable_if_t<is_convertible_v<T2*, T*>>* = nullptr>
74 SharedPtr (SharedPtr<T2>&& from) noexcept;
75
76 private:
77 explicit SharedPtr (const Envelope_& from) noexcept;
78
79 private:
80 template <typename T2>
81 static Envelope_ mkEnvelope_ (T2* from, enable_if_t<is_convertible_v<T2*, Private_::ReferenceCounterContainerType_*>>* = nullptr);
82 template <typename T2>
83 static Envelope_ mkEnvelope_ (T2* from, enable_if_t<!is_convertible_v<T2*, Private_::ReferenceCounterContainerType_*>>* = nullptr);
84
85 public:
86 nonvirtual SharedPtr& operator= (const SharedPtr& rhs) noexcept;
87 nonvirtual SharedPtr& operator= (SharedPtr&& rhs) noexcept;
88
89 public:
90 ~SharedPtr ();
91
92 public:
93 /**
94 */
95 nonvirtual bool IsNull () const noexcept;
96
97 public:
98 /**
99 * Requires that the pointer is non-nullptr. You can call SharedPtr<T,T_TRAITS>::get ()
100 * which whill return null without asserting if the pointer is allowed to be null.</p>
101 */
102 nonvirtual T& GetRep () const noexcept;
103
104 public:
105 /**
106 * \em Note - this CAN NOT return nullptr (because -> semantics are typically invalid for a logically null pointer)
107 */
108 nonvirtual T* operator->() const noexcept;
109
110 public:
111 /**
112 */
113 nonvirtual T& operator* () const noexcept;
114
115 public:
116 /**
117 * Note - this CAN return nullptr
118 */
119 nonvirtual operator T* () const noexcept;
120
121 public:
122 /**
123 * Mimic the 'get' API of the std::auto_ptr&lt;T&gt; class. Just return the pointed to object, with no
124 * asserts about it being non-null.</p>
125 */
126 nonvirtual T* get () const noexcept;
127
128 public:
129 /**
130 * Mimic the 'get' API of the std::auto_ptr&lt;T&gt; class. Make this pointer nullptr, but first return the
131 * pre-existing pointer value. Note - if there were more than one references to the underlying object, its not destroyed.
132 *
133 * NO - Changed API to NOT return old pointer, since COULD have been destroyed, and leads to buggy coding.
134 * If you want the pointer before release, explicitly call get () first!!!
135 */
136 nonvirtual void release () noexcept;
137
138 public:
139 /**
140 * Synonymn for SharedPtr<T,T_TRAITS>::release ()
141 */
142 nonvirtual void clear () noexcept;
143
144 public:
145 /**
146 * Mimic the 'get' API of the std::auto_ptr&lt;T&gt; class. Make this pointer 'p', but first return the
147 * pre-existing pointer value. Unreference any previous value. Note - if there were more than one references
148 * to the underlying object, its not destroyed.
149 */
150 nonvirtual void reset (T* p = nullptr);
151
152 public:
153 /**
154 * Similar to SharedPtr<T2> () CTOR - which does base type. NB couldn't call this dynamic_cast -
155 * thats a reserved word.
156 *
157 * NOTE - THIS RETURNS NULLPTR NOT THROWING - if dynamic_cast<> fails - that is pointer dynamoic_cast not reference
158 */
159 template <typename T2>
160 nonvirtual SharedPtr<T2> Dynamic_Cast () const noexcept;
161
162 public:
163 /**
164 */
165 nonvirtual void swap (SharedPtr& rhs);
166
167 public:
168 /**
169 * Returns true iff reference count of owned pointer is 1 (false if 0 or > 1)
170 */
171 nonvirtual bool IsUnique () const noexcept;
172
173 public:
174 /**
175 * Alias for IsUnique()
176 */
177 nonvirtual bool unique () const noexcept;
178
179 public:
180 /**
181 * I used to keep this available only for debugging, but I've found a few
182 * cases where its handy outside the debugging context so not its awlays available (it has
183 * no cost to keep available).</p>
184 */
185 nonvirtual ReferenceCountType CurrentRefCount () const noexcept;
186
187 public:
188 /**
189 * Alias for CurrentRefCount()
190 */
191 nonvirtual ReferenceCountType use_count () const noexcept;
192
193 public:
194 /**
195 */
196 constexpr bool operator== (const SharedPtr& rhs) const;
197 constexpr bool operator== (nullptr_t) const;
198
199 public:
200 /**
201 */
202 constexpr strong_ordering operator<=> (const SharedPtr& rhs) const;
203
204 public:
205 /**
206 * \brief return true iff *this != nullptr
207 */
208 nonvirtual explicit operator bool () const noexcept;
209
210 private:
211 Envelope_ fEnvelope_;
212
213 private:
214 template <typename T2>
215 friend class SharedPtr;
216
217 private:
218 template <typename T2>
219 friend class enable_shared_from_this;
220 };
221
222 /**
223 * An OPTIONAL class you can mix into 'T', and use with SharedPtr<>. If the 'T' used in SharedPtr<T> inherits
224 * from this, then you can re-constitute a SharedPtr<T> from it's T* (since the count is pulled along-side).
225 * This is sometimes handy if you wish to take a SharedPtr<> object, and pass the underlying pointer through
226 * a layer of code, and then re-constitute the SharedPtr<> part later.
227 *
228 * To enable the shared_from_this () functionality - and allow recovery of the SharedPtr<T> from the T* itself, its necessary to
229 * combine the T type with the SharedPtr<T> infrastructure.
230 *
231 * To use, just inherit your type from enable_shared_from_this<>:
232 *
233 * struct TTT : Memory::enable_shared_from_this<TTT> {
234 * string x;
235 * };
236 * using TTT_SP = SharedPtr<TTT,SharedPtrFromThis_Traits<TTT>> ;
237 *
238 * This is like the std::enable_shared_from_this - making your type inherit from it, allows you to recover the
239 * underlying SharedPtr<> given a plain C++ pointer to T.
240 *
241 */
242 template <typename T>
243 class enable_shared_from_this : public Private_::ReferenceCounterContainerType_ {
244 public:
245 constexpr enable_shared_from_this ();
247
248 public:
249 enable_shared_from_this& operator= (const enable_shared_from_this&) = delete;
250
251 public:
252 ~enable_shared_from_this () = default;
253
254 public:
255 /**
256 */
257 nonvirtual SharedPtr<T> shared_from_this ();
258
259 private:
260 template <typename T2>
261 friend class SharedPtr;
262 };
263
264 /**
265 * Callers can always use EITHER shared_ptr or SharedPtr. But this define tells which is probably faster
266 * for the most part. Often types, users will want to define a typedef which selects
267 * the faster implementation.
268 *
269 * \note As of 2015-10-21, and version v2.0a109, it appears on windows/VS2k13, SharedPtr is about 30% faster,
270 * and GCC 4.9 on ubuntu its about 3% faster (not enough to be significant). This requires more testing
271 * though.
272 *
273 * \note As of 2016-06-09, and version v2.0a148, it appears on windows/VS2k13, SharedPtr is about 10% faster,
274 * and GCC 5.3 on ubuntu its a wash. For now - switch so we default to shared_ptr on gcc and SharedPtr using
275 * vs2k15
276 *
277 * \note As of 2016-07-09, and version v2.0a156 (after SpinLock fence/lockless blockallocation changes), it appears on windows/VS2k13,
278 * SharedPtr is still about 10% faster
279 *
280 * \note As of 2017-10-13 - Stroika v2.0a217, and Visual Studio.Net 2017 (15.4.0) - SharedPtr<> remains about 15% faster than shared_ptr<>
281 * on windows.
282 *
283 * \note As of 2021-02-14 - Stroika v2.1b10 and Visual Studio.Net 2019 (16.8.5) - SharedPtr<> remains about 18% faster than shared_ptr<>
284 * and UNIX / g++ still too close to call - so stick with shared_ptr<>
285 *
286 * \note As of 2021-11-03, Stroika v2.1b14, I switched this to always false. I was testing with shared_ptr<T> (new T ()), as opposed
287 * to make_shared<T> (), and that is obviously unfairly biased. Using make_shared, the stl::shared_ptr is clearly faster,
288 * even on VS2k.
289 *
290 * // @todo GET RID OF in v3 after testing - http://stroika-bugs.sophists.com/browse/STK-967
291 */
292 [[deprecated ("Since Stroika v3.0d8")]] constexpr bool kSharedPtr_IsFasterThan_shared_ptr = false;
293}
294
295namespace std {
296
297 /**
298 * overload the std::dynamic_pointer_cast to work with Stroika SharedPtr<> as well.
299 *
300 * This returns an empty SharedPtr (no throw) if the type cannot be converted with dynamic_cast<>.
301 */
302 template <typename TO_TYPE_T, typename FROM_TYPE_T>
303 Stroika::Foundation::Memory::SharedPtr<TO_TYPE_T> dynamic_pointer_cast (const Stroika::Foundation::Memory::SharedPtr<FROM_TYPE_T>& sp) noexcept;
304
305 /**
306 * overload the std::atomic_load_explicit/atomic_load to work with Stroika SharedPtr<> as well.
307 */
308 template <typename T>
309 Stroika::Foundation::Memory::SharedPtr<T> atomic_load (const Stroika::Foundation::Memory::SharedPtr<T>* copyFrom);
310 template <typename T>
311 Stroika::Foundation::Memory::SharedPtr<T> atomic_load_explicit (const Stroika::Foundation::Memory::SharedPtr<T>* copyFrom, memory_order);
312
313 /**
314 * overload the std::atomic_store_explicit/atomic_store to work with Stroika SharedPtr<> as well.
315 */
316 template <typename T>
317 void atomic_store (Stroika::Foundation::Memory::SharedPtr<T>* storeTo, Stroika::Foundation::Memory::SharedPtr<T> o);
318 template <typename T>
319 void atomic_store_explicit (Stroika::Foundation::Memory::SharedPtr<T>* storeTo, Stroika::Foundation::Memory::SharedPtr<T> o, memory_order);
320
321}
322
323DISABLE_COMPILER_MSC_WARNING_END (4996);
324DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
325DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
326
327#endif /*_Stroika_Foundation_Memory_SharedPtr_h_*/
328
329/*
330 ********************************************************************************
331 ***************************** Implementation Details ***************************
332 ********************************************************************************
333 */
334#include "SharedPtr.inl"
constexpr bool kSharedPtr_IsFasterThan_shared_ptr
Definition SharedPtr.h:292
STL namespace.