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 }
Namespace for the OpenGL implementation of the graphics engine.
Definition: BufferD3D11Impl.h:34
Base class for all reference counting objects.
Definition: RefCountedObjectImpl.h:470