object.h revision 12037
1#if !defined(__OBJECT_H) 2#define __OBJECT_H 3 4#include <atomic> 5#include "constructor_stats.h" 6 7/// Reference counted object base class 8class Object { 9public: 10 /// Default constructor 11 Object() { print_default_created(this); } 12 13 /// Copy constructor 14 Object(const Object &) : m_refCount(0) { print_copy_created(this); } 15 16 /// Return the current reference count 17 int getRefCount() const { return m_refCount; }; 18 19 /// Increase the object's reference count by one 20 void incRef() const { ++m_refCount; } 21 22 /** \brief Decrease the reference count of 23 * the object and possibly deallocate it. 24 * 25 * The object will automatically be deallocated once 26 * the reference count reaches zero. 27 */ 28 void decRef(bool dealloc = true) const { 29 --m_refCount; 30 if (m_refCount == 0 && dealloc) 31 delete this; 32 else if (m_refCount < 0) 33 throw std::runtime_error("Internal error: reference count < 0!"); 34 } 35 36 virtual std::string toString() const = 0; 37protected: 38 /** \brief Virtual protected deconstructor. 39 * (Will only be called by \ref ref) 40 */ 41 virtual ~Object() { print_destroyed(this); } 42private: 43 mutable std::atomic<int> m_refCount { 0 }; 44}; 45 46// Tag class used to track constructions of ref objects. When we track constructors, below, we 47// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for 48// ref_tag. This lets us check that the total number of ref<Anything> constructors/destructors is 49// correct without having to check each individual ref<Whatever> type individually. 50class ref_tag {}; 51 52/** 53 * \brief Reference counting helper 54 * 55 * The \a ref refeference template is a simple wrapper to store a 56 * pointer to an object. It takes care of increasing and decreasing 57 * the reference count of the object. When the last reference goes 58 * out of scope, the associated object will be deallocated. 59 * 60 * \ingroup libcore 61 */ 62template <typename T> class ref { 63public: 64 /// Create a nullptr reference 65 ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); } 66 67 /// Construct a reference from a pointer 68 ref(T *ptr) : m_ptr(ptr) { 69 if (m_ptr) ((Object *) m_ptr)->incRef(); 70 71 print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer"); 72 73 } 74 75 /// Copy constructor 76 ref(const ref &r) : m_ptr(r.m_ptr) { 77 if (m_ptr) 78 ((Object *) m_ptr)->incRef(); 79 80 print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this); 81 } 82 83 /// Move constructor 84 ref(ref &&r) : m_ptr(r.m_ptr) { 85 r.m_ptr = nullptr; 86 87 print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this); 88 } 89 90 /// Destroy this reference 91 ~ref() { 92 if (m_ptr) 93 ((Object *) m_ptr)->decRef(); 94 95 print_destroyed(this); track_destroyed((ref_tag*) this); 96 } 97 98 /// Move another reference into the current one 99 ref& operator=(ref&& r) { 100 print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this); 101 102 if (*this == r) 103 return *this; 104 if (m_ptr) 105 ((Object *) m_ptr)->decRef(); 106 m_ptr = r.m_ptr; 107 r.m_ptr = nullptr; 108 return *this; 109 } 110 111 /// Overwrite this reference with another reference 112 ref& operator=(const ref& r) { 113 print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this); 114 115 if (m_ptr == r.m_ptr) 116 return *this; 117 if (m_ptr) 118 ((Object *) m_ptr)->decRef(); 119 m_ptr = r.m_ptr; 120 if (m_ptr) 121 ((Object *) m_ptr)->incRef(); 122 return *this; 123 } 124 125 /// Overwrite this reference with a pointer to another object 126 ref& operator=(T *ptr) { 127 print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer"); 128 129 if (m_ptr == ptr) 130 return *this; 131 if (m_ptr) 132 ((Object *) m_ptr)->decRef(); 133 m_ptr = ptr; 134 if (m_ptr) 135 ((Object *) m_ptr)->incRef(); 136 return *this; 137 } 138 139 /// Compare this reference with another reference 140 bool operator==(const ref &r) const { return m_ptr == r.m_ptr; } 141 142 /// Compare this reference with another reference 143 bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; } 144 145 /// Compare this reference with a pointer 146 bool operator==(const T* ptr) const { return m_ptr == ptr; } 147 148 /// Compare this reference with a pointer 149 bool operator!=(const T* ptr) const { return m_ptr != ptr; } 150 151 /// Access the object referenced by this reference 152 T* operator->() { return m_ptr; } 153 154 /// Access the object referenced by this reference 155 const T* operator->() const { return m_ptr; } 156 157 /// Return a C++ reference to the referenced object 158 T& operator*() { return *m_ptr; } 159 160 /// Return a const C++ reference to the referenced object 161 const T& operator*() const { return *m_ptr; } 162 163 /// Return a pointer to the referenced object 164 operator T* () { return m_ptr; } 165 166 /// Return a const pointer to the referenced object 167 T* get_ptr() { return m_ptr; } 168 169 /// Return a pointer to the referenced object 170 const T* get_ptr() const { return m_ptr; } 171private: 172 T *m_ptr; 173}; 174 175#endif /* __OBJECT_H */ 176