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

Diligent Engine API Reference

RefCountedObjectImpl.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
28
29 #include "Object.h"
30 #include "Atomics.h"
31 #include "DebugUtilities.h"
32 #include "LockHelper.h"
33 #include "ValidatedCast.h"
34 #include "MemoryAllocator.h"
35
36 namespace Diligent
37 {
38
39 // This class controls the lifetime of a refcounted object
40 class RefCountersImpl : public IReferenceCounters
41 {
42 public:
43 inline virtual CounterValueType AddStrongRef()override final
44 {
45 VERIFY( m_ObjectState == ObjectState::Alive, "Attempting to increment strong reference counter for a destroyed or not itialized object!" );
46 VERIFY( m_ObjectWrapperBuffer[0] != 0 && m_ObjectWrapperBuffer[1] != 0, "Object wrapper is not initialized");
47 return Atomics::AtomicIncrement(m_lNumStrongReferences);
48 }
49
50 inline virtual CounterValueType ReleaseStrongRef()override final
51 {
52 VERIFY( m_ObjectState == ObjectState::Alive, "Attempting to decrement strong reference counter for an object that is not alive" );
53 VERIFY( m_ObjectWrapperBuffer[0] != 0 && m_ObjectWrapperBuffer[1] != 0, "Object wrapper is not initialized");
54
55 // Decrement strong reference counter without acquiring the lock.
56 auto RefCount = Atomics::AtomicDecrement(m_lNumStrongReferences);
57 VERIFY( RefCount >= 0, "Inconsistent call to ReleaseStrongRef()" );
58 if( RefCount == 0 )
59 {
60 // Since RefCount==0, there are no more strong references and the only place
61 // where strong ref counter can be incremented is from GetObject().
62
63 // If several threads were allowed to get to this point, there would
64 // be serious risk that <this> had already been destroyed and m_LockFlag expired.
65 // Consider the following scenario:
66 // |
67 // This thread | Another thread
68 // |
69 // m_lNumStrongReferences == 1
70 // m_lNumWeakReferences == 1
71 // |
72 // 1. Decrement m_lNumStrongReferences |
73 // Read RefCount==0, no lock acquired|
74 // | 1. Run GetObject()
75 // | - acquire the lock
76 // | - increment m_lNumStrongReferences
77 // | - release the lock
78 // |
79 // | 2. Run ReleaseWeakRef()
80 // | - decrement m_lNumWeakReferences
81 // |
82 // | 3. Run ReleaseStrongRef()
83 // | - decrement m_lNumStrongReferences
84 // | - read RefCount==0
85 //
86 // Both threads will get to this point. The first one will destroy <this>
87 // The second one will read expired m_LockFlag
88
89 // IT IS CRUCIALLY IMPORTANT TO ASSURE THAT ONLY ONE THREAD WILL EVER
90 // EXECUTE THIS CODE
91
92 // The sloution is to atomically increment strong ref counter in GetObject().
93 // There are two possible scenarios depending on who first increments the counter:
94
95
96 // Scenario I
97 //
98 // This thread | Another thread - GetObject() | One more thread - GetObject()
99 // | |
100 // m_lNumStrongReferences == 1 |
101 // | |
102 // | 1. Acquire the lock |
103 // 1. Decrement m_lNumStrongReferences | | 1. Wait for the lock
104 // 2. Read RefCount==0 | 2. Increment m_lNumStrongReferences |
105 // 3. Start destroying the object | 3. Read StrongRefCnt == 1 |
106 // 4. Wait for the lock | 4. DO NOT return the reference |
107 // | to the object |
108 // | 5. Decrement m_lNumStrongReferences |
109 // _ _ _ _ _ _ _ _ _ _ _ _ _| 6. Release the lock _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ _ _
110 // | | 2. Acquire the lock
111 // | | 3. Increment m_lNumStrongReferences
112 // | | 4. Read StrongRefCnt == 1
113 // | | 5. DO NOT return the reference
114 // | | to the object
115 // | | 6. Decrement m_lNumStrongReferences
116 // _ _ _ _ _ _ _ _ _ _ _ _ | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | _ 7. Release the lock _ _ _ _ _ _
117 // 5. Acquire the lock | |
118 // - m_lNumStrongReferences==0 | |
119 // 6. DESTROY the object | |
120 // | |
121
122 // GetObject() MUST BE SERIALIZED for this to work properly!
123
124
125 // Scenario II
126 //
127 // This thread | Another thread - GetObject()
128 // |
129 // m_lNumStrongReferences == 1
130 // |
131 // | 1. Acquire the lock
132 // | 2. Increment m_lNumStrongReferences
133 // 1. Decrement m_lNumStrongReferences |
134 // 2. Read RefCount>0 |
135 // 3. DO NOT destroy the object | 3. Read StrongRefCnt > 1 (while m_lNumStrongReferences == 1)
136 // | 4. Return the reference to the object
137 // | - Increment m_lNumStrongReferences
138 // | 5. Decrement m_lNumStrongReferences
139
140 #ifdef _DEBUG
141 Atomics::Long NumStrongRefs = m_lNumStrongReferences;
142 VERIFY( NumStrongRefs == 0 || NumStrongRefs == 1, "Num strong references (", NumStrongRefs, ") is expected to be 0 or 1" );
143 #endif
144
145 // Acquire the lock.
146 ThreadingTools::LockHelper Lock(m_LockFlag);
147
148 // GetObject() first acquires the lock, and only then increments and
149 // decrements the ref counter. If it reads 1 after incremeting the counter,
150 // it does not return the reference to the object and decrements the counter.
151 // If we acquired the lock, GetObject() will not start until we are done
152 VERIFY_EXPR( m_lNumStrongReferences == 0 && m_ObjectState == ObjectState::Alive );
153
154 // Extra caution
155 if(m_lNumStrongReferences == 0 && m_ObjectState == ObjectState::Alive)
156 {
157 VERIFY(m_ObjectWrapperBuffer[0] != 0 && m_ObjectWrapperBuffer[1] != 0, "Object wrapper is not initialized");
158 // We cannot destroy the object while reference counters are locked as this will
159 // cause a deadlock in cases like this:
160 //
161 // A ==sp==> B ---wp---> A
162 //
163 // RefCounters_A.Lock();
164 // delete A{
165 // A.~dtor(){
166 // B.~dtor(){
167 // wpA.ReleaseWeakRef(){
168 // RefCounters_A.Lock(); // Deadlock
169 //
170
171 // So we copy the object wrapper and destroy the object after unlocking the
172 // reference counters
173 size_t ObjectWrapperBufferCopy[ObjectWrapperBufferSize];
174 for(size_t i=0; i < ObjectWrapperBufferSize; ++i)
175 ObjectWrapperBufferCopy[i] = m_ObjectWrapperBuffer[i];
176 #ifdef _DEBUG
177 memset(m_ObjectWrapperBuffer, 0, sizeof(m_ObjectWrapperBuffer));
178 #endif
179 auto *pWrapper = reinterpret_cast<ObjectWrapperBase*>(ObjectWrapperBufferCopy);
180
181 // In a multithreaded environment, reference counters object may
182 // be destroyed at any time while m_pObject->~dtor() is running.
183 // NOTE: m_pObject may not be the only object referencing m_pRefCounters.
184 // All objects that are owned by m_pObject will point to the same
185 // reference counters object.
186
187 // Note that this is the only place where m_ObjectState is
188 // modified after the ref counters object has been created
189 m_ObjectState = ObjectState::Destroyed;
190 // The object is now detached from the reference counters and it is if
191 // it was destroyed since no one can obtain access to it.
192
193
194 // It is essentially important to check the number of weak references
195 // while the object is locked. Otherwise reference counters object
196 // may be destroyed twice if ReleaseWeakRef() is executed by other thread:
197 //
198 // This thread | Another thread - ReleaseWeakRef()
199 // |
200 // 1. Decrement m_lNumStrongReferences,|
201 // m_lNumStrongReferences==0, |
202 // acquire the lock, destroy |
203 // the obj, release the lock |
204 // m_lNumWeakReferences == 1 |
205 // | 1. Aacquire the lock,
206 // | decrement m_lNumWeakReferences,
207 // | m_lNumWeakReferences == 0,
208 // | m_ObjectState == ObjectState::Destroyed
209 // |
210 // 2. Read m_lNumWeakReferences == 0 |
211 // 3. Destroy the ref counters obj | 2. Destroy the ref counters obj
212 //
213 bool bDestroyThis = m_lNumWeakReferences == 0;
214 // ReleaseWeakRef() decrements m_lNumWeakReferences, and checks it for
215 // zero only after acquiring the lock. So if m_lNumWeakReferences==0, no
216 // weak reference-related code may be running
217
218
219 // We must explicitly unlock the object now to avoid deadlocks. Also,
220 // if this is deleted, this->m_LockFlag will expire, which will cause
221 // Lock.~LockHelper() to crash
222 Lock.Unlock();
223
224 // Destroy referenced object
225 pWrapper->DestroyObject();
226
227 // Note that <this> may be destroyed here already,
228 // see comments in ~ControlledObjectType()
229 if( bDestroyThis )
230 SelfDestroy();
231 }
232 }
233
234 return RefCount;
235 }
236
237 inline virtual CounterValueType AddWeakRef()override final
238 {
239 return Atomics::AtomicIncrement(m_lNumWeakReferences);
240 }
241
242 inline virtual CounterValueType ReleaseWeakRef()override final
243 {
244 // The method must be serialized!
245 ThreadingTools::LockHelper Lock(m_LockFlag);
246 // It is essentially important to check the number of weak references
247 // while holding the lock. Otherwise reference counters object
248 // may be destroyed twice if ReleaseStrongRef() is executed by other
249 // thread.
250 auto NumWeakReferences = Atomics::AtomicDecrement(m_lNumWeakReferences);
251 VERIFY( NumWeakReferences >= 0, "Inconsistent call to ReleaseWeakRef()" );
252
253 // There are two special case when we must not destroy the ref counters object even
254 // when NumWeakReferences == 0 && m_lNumStrongReferences == 0 :
255 //
256 // This thread | Another thread - ReleaseStrongRef()
257 // |
258 // 1. Lock the object |
259 // |
260 // 2. Decrement m_lNumWeakReferences, | 1. Decrement m_lNumStrongReferences,
261 // m_lNumWeakReferences==0 | RefCount == 0
262 // |
263 // | 2. Start waiting for the lock to destroy
264 // | the object, m_ObjectState != ObjectState::Destroyed
265 // 3. Do not destroy reference |
266 // counters, unlock |
267 // | 3. Acquire the lock,
268 // | destroy the object,
269 // | read m_lNumWeakReferences==0
270 // | destroy the reference counters
271 //
272
273 // If an exception is thrown during the object construction and there is a weak pointer to the object itself,
274 // we may get to this point, but should not destroy the reference counters, because it will be destroyed by MakeNewRCObj
275 // Consider this example:
276 //
277 // A ==sp==> B ---wp---> A
278 //
279 // MakeNewRCObj::operator()
280 // try
281 // {
282 // A.ctor()
283 // B.ctor()
284 // wp.ctor m_lNumWeakReferences==1
285 // throw
286 // wp.dtor m_lNumWeakReferences==0, destroy this
287 // }
288 // catch(...)
289 // {
290 // Destory ref counters second time
291 // }
292 //
293 if( NumWeakReferences == 0 && /*m_lNumStrongReferences == 0 &&*/ m_ObjectState == ObjectState::Destroyed )
294 {
295 VERIFY_EXPR(m_lNumStrongReferences == 0);
296 VERIFY( m_ObjectWrapperBuffer[0] == 0 && m_ObjectWrapperBuffer[1] == 0, "Object wrapper must be null");
297 // m_ObjectState is set to ObjectState::Destroyed under the lock. If the state is not Destroyed,
298 // ReleaseStrongRef() will take care of it.
299 // Access to Object wrapper and decrementing m_lNumWeakReferences is atomic. Since we acquired the lock,
300 // no other thread can access either of them.
301 // Access to m_lNumStrongReferences is NOT PROTECTED by lock.
302
303 // There are no more references to the ref counters object and the object itself
304 // is already destroyed.
305 // We can safely unlock it and destroy.
306 // If we do not unlock it, this->m_LockFlag will expire,
307 // which will cause Lock.~LockHelper() to crash.
308 Lock.Unlock();
309 SelfDestroy();
310 }
311 return NumWeakReferences;
312 }
313
314 inline virtual void GetObject( class IObject **ppObject )override final
315 {
316 if( m_ObjectState != ObjectState::Alive)
317 return; // Early exit
318
319 // It is essential to INCREMENT REF COUNTER while HOLDING THE LOCK to make sure that
320 // StrongRefCnt > 1 guarantees that the object is alive.
321
322 // If other thread started deleting the object in ReleaseStrongRef(), then m_lNumStrongReferences==0
323 // We must make sure only one thread is allowed to increment the counter to guarantee that if StrongRefCnt > 1,
324 // there is at least one real strong reference left. Otherwise the following scenario may occur:
325 //
326 // m_lNumStrongReferences == 1
327 //
328 // Thread 1 - ReleaseStrongRef() | Thread 2 - GetObject() | Thread 3 - GetObject()
329 // | |
330 // - Decrement m_lNumStrongReferences | -Increment m_lNumStrongReferences | -Increment m_lNumStrongReferences
331 // - Read RefCount == 0 | -Read StrongRefCnt==1 | -Read StrongRefCnt==2
332 // Destroy the object | | -Return reference to the soon
333 // | | to expire object
334 //
335 ThreadingTools::LockHelper Lock(m_LockFlag);
336
337 auto StrongRefCnt = Atomics::AtomicIncrement(m_lNumStrongReferences);
338
339 // Checking if m_ObjectState == ObjectState::Alive only is not reliable:
340 //
341 // This thread | Another thread
342 // |
343 // 1. Acquire the lock |
344 // | 1. Decrement m_lNumStrongReferences
345 // 2. Increment m_lNumStrongReferences | 2. Test RefCount==0
346 // 3. Read StrongRefCnt == 1 | 3. Start destroying the object
347 // m_ObjectState == ObjectState::Alive |
348 // 4. DO NOT return the reference to | 4. Wait for the lock, m_ObjectState == ObjectState::Alive
349 // the object |
350 // 5. Decrement m_lNumStrongReferences |
351 // | 5. Destroy the object
352
353 if( m_ObjectState == ObjectState::Alive && StrongRefCnt > 1 )
354 {
355 VERIFY( m_ObjectWrapperBuffer[0] != 0 && m_ObjectWrapperBuffer[1] != 0, "Object wrapper is not initialized");
356 // QueryInterface() must not lock the object, or a deadlock happens.
357 // The only other two methods that lock the object are ReleaseStrongRef()
358 // and ReleaseWeakRef(), which are never called by QueryInterface()
359 auto *pWrapper = reinterpret_cast<ObjectWrapperBase*>(m_ObjectWrapperBuffer);
360 pWrapper->QueryInterface(Diligent::IID_Unknown, ppObject);
361 }
362 Atomics::AtomicDecrement(m_lNumStrongReferences);
363 }
364
365 inline virtual CounterValueType GetNumStrongRefs()const override final
366 {
367 return m_lNumStrongReferences;
368 }
369
370 inline virtual CounterValueType GetNumWeakRefs()const override final
371 {
372 return m_lNumWeakReferences;
373 }
374
375 private:
376 template<typename AllocatorType, typename ObjectType>
377 friend class MakeNewRCObj;
378
379 RefCountersImpl()noexcept
380 {
381 m_lNumStrongReferences = 0;
382 m_lNumWeakReferences = 0;
383 #ifdef _DEBUG
384 memset(m_ObjectWrapperBuffer, 0, sizeof(m_ObjectWrapperBuffer));
385 #endif
386 }
387
388 class ObjectWrapperBase
389 {
390 public:
391 virtual void DestroyObject() = 0;
392 virtual void QueryInterface( const Diligent::INTERFACE_ID &iid, IObject **ppInterface )=0;
393 };
394
395 template<typename ObjectType, typename AllocatorType>
396 class ObjectWrapper : public ObjectWrapperBase
397 {
398 public:
399 ObjectWrapper(ObjectType *pObject, AllocatorType *pAllocator)noexcept :
400 m_pObject(pObject),
401 m_pAllocator(pAllocator)
402 {}
403 virtual void DestroyObject()override final
404 {
405 if (m_pAllocator)
406 {
407 m_pObject->~ObjectType();
408 m_pAllocator->Free(m_pObject);
409 }
410 else
411 {
412 delete m_pObject;
413 }
414 }
415 virtual void QueryInterface( const Diligent::INTERFACE_ID &iid, IObject **ppInterface )override final
416 {
417 return m_pObject->QueryInterface(iid, ppInterface);
418 }
419 private:
420 // It is crucially important that the type of the pointer
421 // is ObjectType and not IObject, since the latter
422 // does not have virtual dtor.
423 ObjectType* const m_pObject;
424 AllocatorType * const m_pAllocator;
425 };
426
427 template<typename ObjectType, typename AllocatorType>
428 void Attach(ObjectType *pObject, AllocatorType *pAllocator)
429 {
430 VERIFY(m_ObjectState == ObjectState::NotInitialized, "Object has already been attached");
431 static_assert(sizeof(ObjectWrapper<ObjectType, AllocatorType>) == sizeof(m_ObjectWrapperBuffer), "Unexpected object wrapper size");
432 new(m_ObjectWrapperBuffer) ObjectWrapper<ObjectType, AllocatorType>(pObject, pAllocator);
433 m_ObjectState = ObjectState::Alive;
434 }
435
436 void SelfDestroy()
437 {
438 delete this;
439 }
440
441 ~RefCountersImpl()
442 {
443 VERIFY( m_lNumStrongReferences == 0 && m_lNumWeakReferences == 0,
444 "There exist outstanding references to the object being destroyed" );
445 }
446
447 // No copies/moves
448 RefCountersImpl(const RefCountersImpl&) = delete;
449 RefCountersImpl(RefCountersImpl&&) = delete;
450 RefCountersImpl& operator = (const RefCountersImpl&) = delete;
451 RefCountersImpl& operator = (RefCountersImpl&&) = delete;
452
453 static constexpr size_t ObjectWrapperBufferSize = sizeof(ObjectWrapper<IObject, IMemoryAllocator>) / sizeof(size_t);
454 size_t m_ObjectWrapperBuffer[ObjectWrapperBufferSize];
455 Atomics::AtomicLong m_lNumStrongReferences;
456 Atomics::AtomicLong m_lNumWeakReferences;
457 ThreadingTools::LockFlag m_LockFlag;
458 enum class ObjectState : Int32
459 {
460 NotInitialized,
461 Alive,
462 Destroyed
463 };
464 volatile ObjectState m_ObjectState = ObjectState::NotInitialized;
465 };
466
467
469 template<typename Base>
470 class RefCountedObject : public Base
471 {
472 public:
473 using CounterValueType = IReferenceCounters::CounterValueType;
474
475 RefCountedObject(IReferenceCounters *pRefCounters)noexcept :
476 m_pRefCounters( ValidatedCast<RefCountersImpl>(pRefCounters) )
477 {
478 // If object is allocated on stack, ref counters will be null
479 //VERIFY(pRefCounters != nullptr, "Reference counters must not be null")
480 }
481
482 // Virtual destructor makes sure all derived classes can be destroyed
483 // through the pointer to the base class
484 virtual ~RefCountedObject()
485 {
486 // WARNING! m_pRefCounters may be expired in scenarios like this:
487 //
488 // A ==sp==> B ---wp---> A
489 //
490 // RefCounters_A.ReleaseStrongRef(){ // NumStrongRef == 0, NumWeakRef == 1
491 // bDestroyThis = (m_lNumWeakReferences == 0) == false;
492 // delete A{
493 // A.~dtor(){
494 // B.~dtor(){
495 // wpA.ReleaseWeakRef(){ // NumStrongRef == 0, NumWeakRef == 0, m_pObject==nullptr
496 // delete RefCounters_A;
497 // ...
498 // VERIFY( m_pRefCounters->GetNumStrongRefs() == 0 // Access violation!
499
500 // This also may happen if one thread is executing ReleaseStrongRef(), while
501 // another one is simultaneously running ReleaseWeakRef().
502
503 //VERIFY( m_pRefCounters->GetNumStrongRefs() == 0,
504 // "There remain strong references to the object being destroyed" );
505 }
506
507 inline virtual IReferenceCounters* GetReferenceCounters()const override final
508 {
509 VERIFY_EXPR(m_pRefCounters != nullptr);
510 return m_pRefCounters;
511 }
512
513 inline virtual CounterValueType AddRef()override final
514 {
515 VERIFY_EXPR(m_pRefCounters != nullptr);
516 // Since type of m_pRefCounters is RefCountersImpl,
517 // this call will not be virtual and should be inlined
518 return m_pRefCounters->AddStrongRef();
519 }
520
521 inline virtual CounterValueType Release()override
522 {
523 VERIFY_EXPR(m_pRefCounters != nullptr);
524 // Since type of m_pRefCounters is RefCountersImpl,
525 // this call will not be virtual and should be inlined
526 return m_pRefCounters->ReleaseStrongRef();
527 }
528
529 protected:
530 template<typename AllocatorType, typename ObjectType>
531 friend class MakeNewRCObj;
532
533 friend class RefCountersImpl;
534
535
536 // Operator delete can only be called from MakeNewRCObj if an exception is thrown,
537 // or from RefCountersImpl when object is destroyed
538 // It needs to be protected (not private!) to allow generation of destructors in derived classes
539
540 void operator delete(void *ptr)
541 {
542 delete[] reinterpret_cast<Uint8*>(ptr);
543 }
544
545 template<typename ObjectAllocatorType>
546 void operator delete(void *ptr, ObjectAllocatorType &Allocator, const Char* dbgDescription, const char* dbgFileName, const Int32 dbgLineNumber)
547 {
548 return Allocator.Free(ptr);
549 }
550
551 private:
552 // Operator new is private, and can only be called by MakeNewRCObj
553
554 void* operator new(size_t Size)
555 {
556 return new Uint8[Size];
557 }
558
559 template<typename ObjectAllocatorType>
560 void* operator new(size_t Size, ObjectAllocatorType &Allocator, const Char* dbgDescription, const char* dbgFileName, const Int32 dbgLineNumber)
561 {
562 return Allocator.Allocate(Size, dbgDescription, dbgFileName, dbgLineNumber);
563 }
564
565
566 // Note that the type of the reference counters is RefCountersImpl,
567 // not IReferenceCounters. This avoids virtual calls from
568 // AddRef() and Release() methods
569 RefCountersImpl *const m_pRefCounters;
570 };
571
572
573 template<typename ObjectType, typename AllocatorType = IMemoryAllocator>
574 class MakeNewRCObj
575 {
576 public:
577 MakeNewRCObj(AllocatorType &Allocator, const Char* dbgDescription, const char* dbgFileName, const Int32 dbgLineNumber, IObject* pOwner = nullptr)noexcept :
578 m_pAllocator(&Allocator),
579 m_pOwner(pOwner),
580 m_dbgDescription(dbgDescription),
581 m_dbgFileName(dbgFileName),
582 m_dbgLineNumber(dbgLineNumber)
583 {
584 }
585
586 MakeNewRCObj(IObject* pOwner = nullptr)noexcept :
587 m_pAllocator(nullptr),
588 m_pOwner(pOwner),
589 m_dbgDescription(nullptr),
590 m_dbgFileName(nullptr),
591 m_dbgLineNumber(0)
592 {}
593
594 MakeNewRCObj(const MakeNewRCObj&) = delete;
595 MakeNewRCObj(MakeNewRCObj&&) = delete;
596 MakeNewRCObj& operator=(const MakeNewRCObj&) = delete;
597 MakeNewRCObj& operator=(MakeNewRCObj&&) = delete;
598
599 template<typename ... CtorArgTypes>
600 ObjectType* operator() (CtorArgTypes&& ... CtorArgs)
601 {
602 RefCountersImpl *pNewRefCounters = nullptr;
603 IReferenceCounters *pRefCounters = nullptr;
604 if(m_pOwner != nullptr)
605 pRefCounters = m_pOwner->GetReferenceCounters();
606 else
607 {
608 // Constructor of RefCountersImpl class is private and only accessible
609 // by methods of MakeNewRCObj
610 pNewRefCounters = new RefCountersImpl();
611 pRefCounters = pNewRefCounters;
612 }
613 ObjectType *pObj = nullptr;
614 try
615 {
616 // Operators new and delete of RefCountedObject are private and only accessible
617 // by methods of MakeNewRCObj
618 if(m_pAllocator)
619 pObj = new(*m_pAllocator, m_dbgDescription, m_dbgFileName, m_dbgLineNumber) ObjectType(pRefCounters, std::forward<CtorArgTypes>(CtorArgs)... );
620 else
621 pObj = new ObjectType( pRefCounters, std::forward<CtorArgTypes>(CtorArgs)... );
622 if(pNewRefCounters != nullptr)
623 pNewRefCounters->Attach<ObjectType, AllocatorType>(pObj, m_pAllocator);
624 }
625 catch (...)
626 {
627 if(pNewRefCounters != nullptr)
628 pNewRefCounters->SelfDestroy();
629 throw;
630 }
631 return pObj;
632 }
633
634 private:
635 AllocatorType* const m_pAllocator;
636 IObject* const m_pOwner;
637 const Char* const m_dbgDescription;
638 const char* const m_dbgFileName;
639 const Int32 m_dbgLineNumber;
640 };
641
642 #define NEW_RC_OBJ(Allocator, Desc, Type, ...) MakeNewRCObj<Type, typename std::remove_reference<decltype(Allocator)>::type>(Allocator, Desc, __FILE__, __LINE__, ##__VA_ARGS__)
643
644 }
Diligent
Namespace for the OpenGL implementation of the graphics engine.
Definition: BufferD3D11Impl.h:34
Diligent::RefCountedObject
Base class for all reference counting objects.
Definition: RefCountedObjectImpl.h:470