ref_ptr.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2010-2011 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // Distributed under:
  6. //
  7. // the Boost Software License, Version 1.0.
  8. // (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // or (at your opinion) under:
  12. //
  13. // The MIT License
  14. // (See accompanying file MIT.txt or a copy at
  15. // http://www.opensource.org/licenses/mit-license.php)
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #ifndef CPPDB_REF_PTR_H
  19. #define CPPDB_REF_PTR_H
  20. #include <cppdb/errors.h>
  21. #include <atomic>
  22. namespace cppdb {
  23. ///
  24. /// \brief This is a smart intrusive reference counting pointer that throws a error on empty
  25. /// access.
  26. ///
  27. /// The T should follow these concepts:
  28. ///
  29. /// \code
  30. /// T::add_ref() // increases reference count
  31. /// IntegerType T::del_ref() // decreases reference count and returns its current value
  32. /// static T::dispose(T *) // destroys the object
  33. /// \endcode
  34. ///
  35. template<typename T>
  36. class ref_ptr {
  37. public:
  38. ///
  39. /// Default create a new object, if v is not null increases its reference count and stores it
  40. ///
  41. ref_ptr(T *v=0) : p(0)
  42. {
  43. reset(v);
  44. }
  45. ///
  46. /// Dereference the object, if reference count goes to 0 destroys it calling T::dispose
  47. ///
  48. ~ref_ptr()
  49. {
  50. reset();
  51. }
  52. ///
  53. /// Copy a pointer
  54. ///
  55. ref_ptr(ref_ptr const &other) : p(0)
  56. {
  57. reset(other.p);
  58. }
  59. ///
  60. /// Assign a pointer
  61. ///
  62. ref_ptr const &operator=(ref_ptr const &other)
  63. {
  64. reset(other.p);
  65. return *this;
  66. }
  67. // Borland warns on assignments using operator=(ref_ptr...) with new sometype(...).
  68. #ifdef __BORLANDC__
  69. ref_ptr const &operator=(T *other)
  70. {
  71. reset(other);
  72. return *this;
  73. }
  74. #endif
  75. ///
  76. /// Get he pointer value, it may return NULL in case of empty pointer
  77. ///
  78. T *get() const
  79. {
  80. return p;
  81. }
  82. ///
  83. /// Cast to boolean type: check if the pointer is not empty in similar way as you check ordinary pointers.
  84. ///
  85. operator bool() const
  86. {
  87. return p!=0;
  88. }
  89. ///
  90. /// Returns pointer to object, throws cppdb_error if it is NULL
  91. ///
  92. T *operator->() const
  93. {
  94. if(!p)
  95. throw cppdb_error("cppdb::ref_ptr: attempt to access an empty object");
  96. return p;
  97. }
  98. ///
  99. /// Returns reference to object, throws cppdb_error if it is NULL
  100. ///
  101. T &operator*() const
  102. {
  103. if(!p)
  104. throw cppdb_error("cppdb::ref_ptr: attempt to access an empty object");
  105. return *p;
  106. }
  107. ///
  108. /// Reset the pointer with new value - old object is dereferenced new is added.
  109. ///
  110. void reset(T *v=0)
  111. {
  112. if(v==p)
  113. return;
  114. if(p) {
  115. if(p->del_ref() == 0) {
  116. T::dispose(p);
  117. }
  118. p=0;
  119. }
  120. if(v) {
  121. v->add_ref();
  122. }
  123. p=v;
  124. }
  125. private:
  126. T *p;
  127. };
  128. ///
  129. /// \brief This is a class that implements reference counting and designed to be used with ref_ptr
  130. ///
  131. class ref_counted {
  132. public:
  133. ///
  134. /// Create an object with 0 reference count
  135. ///
  136. ref_counted() : count_(0)
  137. {
  138. }
  139. ///
  140. /// Virtual destructor - for convenience
  141. ///
  142. virtual ~ref_counted()
  143. {
  144. }
  145. ///
  146. /// Increase reference count
  147. ///
  148. long add_ref()
  149. {
  150. return ++count_;
  151. }
  152. ///
  153. /// Get reference count
  154. ///
  155. long use_count() const
  156. {
  157. long val = count_;
  158. return val;
  159. }
  160. ///
  161. /// Decrease reference count
  162. ///
  163. long del_ref()
  164. {
  165. return --count_;
  166. }
  167. ///
  168. /// Delete the object
  169. ///
  170. static void dispose(ref_counted *p)
  171. {
  172. delete p;
  173. }
  174. private:
  175. std::atomic<long> count_;
  176. };
  177. } // cppdb
  178. #endif