Diligent Engine API Reference: D:/GitHub/DiligentEngine/DiligentCore/Common/interface/RefCntAutoPtr.h Source File

Diligent Engine API Reference

RefCntAutoPtr.h
1 /* Copyright 2015-2018 Egor Yusov
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
12 *
13 * In no event and under no legal theory, whether in tort (including negligence),
14 * contract, or otherwise, unless required by applicable law (such as deliberate
15 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
16 * liable for any damages, including any direct, indirect, special, incidental,
17 * or consequential damages of any character arising as a result of this License or
18 * out of the use or inability to use the software (including but not limited to damages
19 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
20 * all other commercial damages or losses), even if such Contributor has been advised
21 * of the possibility of such damages.
22 */
23
24 #pragma once
25
26 #include "DebugUtilities.h"
27 #include "LockHelper.h"
28 #include "Atomics.h"
29 #include "ValidatedCast.h"
30 #include "RefCountedObjectImpl.h"
31 #include "Object.h"
32
33 namespace Diligent
34 {
35
36
37 template <typename T>
38 class RefCntWeakPtr;
39
40 // The main advantage of RefCntAutoPtr over the std::shared_ptr is that you can
41 // attach the same raw pointer to different smart pointers.
42 //
43 // For instance, the following code will crash since p will be released twice:
44 //
45 // auto *p = new char;
46 // std::shared_ptr<char> pTmp1(p);
47 // std::shared_ptr<char> pTmp2(p);
48 // ...
49
50 // This code, in contrast, works perfectly fine:
51 //
52 // ObjectBase *pRawPtr(new ObjectBase);
53 // RefCntAutoPtr<ObjectBase> pSmartPtr1(pRawPtr);
54 // RefCntAutoPtr<ObjectBase> pSmartPtr2(pRawPtr);
55 // ...
56
57 // Other advantage is that weak pointers remain valid until the
58 // object is alive, even if all smart pointers were destroyed:
59 //
60 // RefCntWeakPtr<ObjectBase> pWeakPtr(pSmartPtr1);
61 // pSmartPtr1.Release();
62 // auto pSmartPtr3 = pWeakPtr.Lock();
63 // ..
64
65 // Weak pointers can also be attached directly to the object:
66 // RefCntWeakPtr<ObjectBase> pWeakPtr(pRawPtr);
67 //
68
70 template <typename T>
71 class RefCntAutoPtr
72 {
73 public:
74 explicit RefCntAutoPtr(T *pObj = nullptr) :
75 m_pObject(pObj)
76 {
77 if( m_pObject )
78 m_pObject->AddRef();
79 }
80
81 RefCntAutoPtr(IObject *pObj, const INTERFACE_ID &IID) :
82 m_pObject(nullptr)
83 {
84 if(pObj)
85 pObj->QueryInterface( IID, reinterpret_cast<IObject**>(&m_pObject) );
86 }
87
88 RefCntAutoPtr(const RefCntAutoPtr &AutoPtr) :
89 m_pObject(AutoPtr.m_pObject)
90 {
91 if(m_pObject)
92 m_pObject->AddRef();
93 }
94
95 RefCntAutoPtr(RefCntAutoPtr &&AutoPtr) :
96 m_pObject(std::move(AutoPtr.m_pObject))
97 {
98 //Make sure original pointer has no references to the object
99 AutoPtr.m_pObject = nullptr;
100 }
101
102 ~RefCntAutoPtr()
103 {
104 Release();
105 }
106
107 void swap(RefCntAutoPtr &AutoPtr)
108 {
109 std::swap(m_pObject, AutoPtr.m_pObject);
110 }
111
112 void Attach(T *pObj)
113 {
114 Release();
115 m_pObject = pObj;
116 }
117
118 T* Detach()
119 {
120 T* pObj = m_pObject;
121 m_pObject = nullptr;
122 return pObj;
123 }
124
125 void Release()
126 {
127 if( m_pObject )
128 {
129 m_pObject->Release();
130 m_pObject = nullptr;
131 }
132 }
133
134 RefCntAutoPtr& operator = (T *pObj)
135 {
136 if( static_cast<T*>(*this) == pObj )
137 return *this;
138
139 return operator= (RefCntAutoPtr(pObj));
140 }
141
142 RefCntAutoPtr& operator = (const RefCntAutoPtr &AutoPtr)
143 {
144 if( *this == AutoPtr )
145 return *this;
146
147 Release();
148 m_pObject = AutoPtr.m_pObject;
149 if(m_pObject)
150 m_pObject->AddRef();
151
152 return *this;
153 }
154
155 RefCntAutoPtr& operator = (RefCntAutoPtr &&AutoPtr)
156 {
157 if( *this == AutoPtr )
158 return *this;
159
160 Release();
161 m_pObject = std::move( AutoPtr.m_pObject );
162 //Make sure original pointer has no references to the object
163 AutoPtr.m_pObject = nullptr;
164 return *this;
165 }
166
167 // All the access functions do not require locking reference counters pointer because if it is valid,
168 // the smart pointer holds strong reference to the object and it thus cannot be released by
169 // ohter thread
170 bool operator ! () const{return m_pObject == nullptr;}
171 operator bool () const{return m_pObject != nullptr;}
172 bool operator == (const RefCntAutoPtr& Ptr)const{return m_pObject == Ptr.m_pObject;}
173 bool operator != (const RefCntAutoPtr& Ptr)const{return m_pObject != Ptr.m_pObject;}
174 bool operator < (const RefCntAutoPtr& Ptr)const{return static_cast<const T*>(*this) < static_cast<const T*>(Ptr);}
175
176 T& operator * () { return *m_pObject; }
177 const T& operator * ()const { return *m_pObject; }
178
179 T* RawPtr() { return m_pObject; }
180 const T* RawPtr()const{ return m_pObject; }
181
182 operator T* () { return RawPtr(); }
183 operator const T* ()const { return RawPtr(); }
184
185 T* operator -> () { return m_pObject; }
186 const T* operator -> ()const{ return m_pObject; }
187
188 private:
189 // Note that the DoublePtrHelper is a private class, and can be created only by RefCntWeakPtr
190 // Thus if no special effort is made, the lifetime of the instances of this class cannot be
191 // longer than the lifetime of the creating object
192 class DoublePtrHelper
193 {
194 public:
195 DoublePtrHelper(RefCntAutoPtr &AutoPtr) :
196 NewRawPtr( static_cast<T*>(AutoPtr) ),
197 m_pAutoPtr( std::addressof(AutoPtr) )
198 {
199 }
200
201 DoublePtrHelper(DoublePtrHelper&& Helper) :
202 NewRawPtr(Helper.NewRawPtr),
203 m_pAutoPtr(Helper.m_pAutoPtr)
204 {
205 Helper.m_pAutoPtr = nullptr;
206 Helper.NewRawPtr = nullptr;
207 }
208
209 ~DoublePtrHelper()
210 {
211 if( m_pAutoPtr && static_cast<T*>(*m_pAutoPtr) != NewRawPtr )
212 {
213 m_pAutoPtr->Attach(NewRawPtr);
214 }
215 }
216
217 T*& operator*(){return NewRawPtr;}
218 const T* operator*()const{return NewRawPtr;}
219
220 operator T**(){return &NewRawPtr;}
221 operator const T**()const{return &NewRawPtr;}
222 private:
223 T *NewRawPtr;
224 RefCntAutoPtr *m_pAutoPtr;
225 DoublePtrHelper(const DoublePtrHelper&);
226 DoublePtrHelper& operator = (const DoublePtrHelper&);
227 DoublePtrHelper& operator = (DoublePtrHelper&&);
228 };
229
230 public:
231 DoublePtrHelper operator& ()
232 {
233 return DoublePtrHelper(*this);
234 }
235
236 const DoublePtrHelper operator& ()const
237 {
238 return DoublePtrHelper(*this);
239 }
240
241 T** GetRawDblPtr() {return &m_pObject;}
242 const T** GetRawDblPtr()const{return &m_pObject;}
243
244 private:
245 T *m_pObject;
246 };
247
249 template <typename T>
250 class RefCntWeakPtr
251 {
252 public:
253 explicit RefCntWeakPtr(T *pObj = nullptr) :
254 m_pObject(pObj),
255 m_pRefCounters(nullptr)
256 {
257 if( m_pObject )
258 {
259 m_pRefCounters = ValidatedCast<RefCountersImpl>( m_pObject->GetReferenceCounters() );
260 m_pRefCounters->AddWeakRef();
261 }
262 }
263
264 ~RefCntWeakPtr()
265 {
266 Release();
267 }
268
269 RefCntWeakPtr(const RefCntWeakPtr& WeakPtr) :
270 m_pObject(WeakPtr.m_pObject),
271 m_pRefCounters(WeakPtr.m_pRefCounters)
272 {
273 if( m_pRefCounters )
274 m_pRefCounters->AddWeakRef();
275 }
276
277 RefCntWeakPtr(RefCntWeakPtr&& WeakPtr) :
278 m_pObject(std::move(WeakPtr.m_pObject)),
279 m_pRefCounters(std::move(WeakPtr.m_pRefCounters))
280 {
281 WeakPtr.m_pRefCounters = nullptr;
282 WeakPtr.m_pObject = nullptr;
283 }
284
285 explicit RefCntWeakPtr(RefCntAutoPtr<T>& AutoPtr) :
286 m_pObject( static_cast<T*>(AutoPtr) ),
287 m_pRefCounters(AutoPtr ? ValidatedCast<RefCountersImpl>( AutoPtr->GetReferenceCounters() ) : nullptr)
288 {
289 if( m_pRefCounters )
290 m_pRefCounters->AddWeakRef();
291 }
292
293 RefCntWeakPtr& operator = (const RefCntWeakPtr& WeakPtr)
294 {
295 if( *this == WeakPtr )
296 return *this;
297
298 Release();
299 m_pObject = WeakPtr.m_pObject;
300 m_pRefCounters = WeakPtr.m_pRefCounters;
301 if( m_pRefCounters )
302 m_pRefCounters->AddWeakRef();
303 return *this;
304 }
305
306 RefCntWeakPtr& operator = (T *pObj)
307 {
308 return operator= (RefCntWeakPtr(pObj));
309 }
310
311 RefCntWeakPtr& operator = (RefCntWeakPtr&& WeakPtr)
312 {
313 if( *this == WeakPtr )
314 return *this;
315
316 Release();
317 m_pObject = std::move(WeakPtr.m_pObject);
318 m_pRefCounters = std::move(WeakPtr.m_pRefCounters);
319 WeakPtr.m_pRefCounters = nullptr;
320 WeakPtr.m_pObject = nullptr;
321 return *this;
322 }
323
324 RefCntWeakPtr& operator = (RefCntAutoPtr<T>& AutoPtr)
325 {
326 Release();
327 m_pObject = static_cast<T*>( AutoPtr );
328 m_pRefCounters = m_pObject ? ValidatedCast<RefCountersImpl>( m_pObject->GetReferenceCounters() ) : nullptr;
329 if( m_pRefCounters )
330 m_pRefCounters->AddWeakRef();
331 return *this;
332 }
333
334 void Release()
335 {
336 if( m_pRefCounters )
337 m_pRefCounters->ReleaseWeakRef();
338 m_pRefCounters = nullptr;
339 m_pObject = nullptr;
340 }
341
345 bool IsValid()
346 {
347 return m_pObject != nullptr && m_pRefCounters != nullptr && m_pRefCounters->GetNumStrongRefs() > 0;
348 }
349
351 RefCntAutoPtr<T> Lock()
352 {
353 RefCntAutoPtr<T> spObj;
354 if( m_pRefCounters )
355 {
356 // Try to obtain pointer to the owner object.
357 // spOwner is only used to keep the object
358 // alive while obtaining strong reference from
359 // the raw pointer m_pObject
360 RefCntAutoPtr<Diligent::IObject> spOwner;
361 m_pRefCounters->GetObject( &spOwner );
362 if( spOwner )
363 {
364 // If owner is alive, we can use our RAW pointer to
365 // create strong reference
366 spObj = m_pObject;
367 }
368 else
369 {
370 // Owner object has been destroyed. There is no reason
371 // to keep this weak reference anymore
372 Release();
373 }
374 }
375 return spObj;
376 }
377
378 bool operator == (const RefCntWeakPtr& Ptr)const{return m_pRefCounters == Ptr.m_pRefCounters;}
379 bool operator != (const RefCntWeakPtr& Ptr)const{return m_pRefCounters != Ptr.m_pRefCounters;}
380
381 protected:
382 RefCountersImpl *m_pRefCounters;
383 // We need to store raw pointer to object itself,
384 // because if the object is owned by another object,
385 // m_pRefCounters->GetObject( &pObj ) will return
386 // pointer to owner, which is not what we need.
387 T *m_pObject;
388 };
389
390 }
Diligent
Namespace for the OpenGL implementation of the graphics engine.
Definition: BufferD3D11Impl.h:34
std
Definition: AdvancedMath.h:316
Diligent::RefCntWeakPtr::Lock
RefCntAutoPtr< T > Lock()
Obtains a strong reference to the object.
Definition: RefCntAutoPtr.h:351
Diligent::RefCntWeakPtr
Implementation of weak pointers.
Definition: RefCntAutoPtr.h:38
Diligent::RefCntAutoPtr
Template class that implements reference counting.
Definition: RefCntAutoPtr.h:71
Diligent::RefCntWeakPtr::IsValid
bool IsValid()
Definition: RefCntAutoPtr.h:345