1 #ifndef CAL_REF_COUNTED_H
2 #define CAL_REF_COUNTED_H
3 
4 
5 #include "cal3d/platform.h"
6 
7 
8 namespace cal3d
9 {
10 
11   template<typename T> class RefPtr;
12 
13   /**
14    * Derive from RefCounted to make your class have reference-counted
15    * lifetime semantics.  Use RefPtr to manage references.  (Don't
16    * call incRef() or decRef() directly.)  When deriving from
17    * RefCounted, make your destructor protected so manual deletion
18    * won't happen on accident.
19    *
20    * Note:  The reference count is initialized to 0.  This makes sense,
21    * because, at object construction, no RefPtrs have referenced the
22    * object.  However, this can cause trouble if you (indirectly) make
23    * a RefPtr to 'this' within your constructor.  When the refptr goes
24    * out of scope, the count goes back to 0, and the object is deleted
25    * before it even exits the constructor.  Current recommended solution:
26    * Don't make refptrs to 'this'.  Pass 'this' by raw pointer and such.
27    */
28   class CAL3D_API RefCounted
29   {
30     template<typename T> friend T* explicitIncRef(T* p);
31     friend void explicitDecRef(RefCounted* p);
32 
33   protected:
RefCounted()34     RefCounted()
35       : m_refCount(0)
36     {
37     }
38 
39     /**
40      * Protected so users of refcounted classes don't use std::auto_ptr
41      * or the delete operator.
42      *
43      * Interfaces that derive from RefCounted should define an inline,
44      * empty, protected destructor as well.
45      */
~RefCounted()46     virtual ~RefCounted()
47     {
48       assert(m_refCount == 0 && "_refCount nonzero in destructor");
49     }
50 
51   // Must use RefPtr instead of manually calling incRef() and decRef().
52   private:
incRef()53     void incRef()
54     {
55       assert(m_refCount >= 0 && "_refCount is less than zero in incRef()!");
56       ++m_refCount;
57     }
58 
59     /**
60      * Remove a reference from the internal reference count.  When this
61      * reaches 0, the object is destroyed.
62      */
decRef()63     void decRef()
64     {
65       assert(m_refCount > 0 &&
66              "_refCount is less than or equal to zero in decRef()!");
67       if (--m_refCount == 0)
68       {
69         delete this;
70       }
71     }
72 
73   public:
getRefCount()74     int getRefCount() const
75     {
76       return m_refCount;
77     }
78 
79   private:
80     // Copying a RefCounted object must be done manually by the
81     // subclass.  Otherwise the refCount gets copied too, and
82     // that's Bad.
83     RefCounted(const RefCounted& rhs);
84     RefCounted& operator=(const RefCounted& rhs);
85 
86   private:
87     int m_refCount;
88   };
89 
90   template<typename T>
explicitIncRef(T * p)91   T* explicitIncRef(T* p)
92   {
93     p->incRef();
94     return p;
95   }
96 
explicitDecRef(RefCounted * p)97   inline void explicitDecRef(RefCounted* p)
98   {
99     p->decRef();
100   }
101 
102 }
103 
104 
105 #endif
106