ref_ptr 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
  2. *
  3. * This library is open source and may be redistributed and/or modified under
  4. * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
  5. * (at your option) any later version. The full license is in LICENSE file
  6. * included with this distribution, and on the openscenegraph.org website.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * OpenSceneGraph Public License for more details.
  12. */
  13. #ifndef OSG_REF_PTR
  14. #define OSG_REF_PTR 1
  15. #include <osg/Config>
  16. #ifdef OSG_USE_REF_PTR_SAFE_DEREFERENCE
  17. #include <typeinfo>
  18. #include <stdexcept>
  19. #include <string>
  20. #endif
  21. namespace osg {
  22. template<typename T> class observer_ptr;
  23. /** Smart pointer for handling referenced counted objects.*/
  24. template<class T>
  25. class ref_ptr
  26. {
  27. public:
  28. typedef T element_type;
  29. ref_ptr() : _ptr(0) {}
  30. ref_ptr(T* ptr) : _ptr(ptr) { if (_ptr) _ptr->ref(); }
  31. ref_ptr(const ref_ptr& rp) : _ptr(rp._ptr) { if (_ptr) _ptr->ref(); }
  32. template<class Other> ref_ptr(const ref_ptr<Other>& rp) : _ptr(rp._ptr) { if (_ptr) _ptr->ref(); }
  33. ref_ptr(observer_ptr<T>& optr) : _ptr(0) { optr.lock(*this); }
  34. ~ref_ptr() { if (_ptr) _ptr->unref(); _ptr = 0; }
  35. ref_ptr& operator = (const ref_ptr& rp)
  36. {
  37. assign(rp);
  38. return *this;
  39. }
  40. template<class Other> ref_ptr& operator = (const ref_ptr<Other>& rp)
  41. {
  42. assign(rp);
  43. return *this;
  44. }
  45. inline ref_ptr& operator = (T* ptr)
  46. {
  47. if (_ptr==ptr) return *this;
  48. T* tmp_ptr = _ptr;
  49. _ptr = ptr;
  50. if (_ptr) _ptr->ref();
  51. // unref second to prevent any deletion of any object which might
  52. // be referenced by the other object. i.e rp is child of the
  53. // original _ptr.
  54. if (tmp_ptr) tmp_ptr->unref();
  55. return *this;
  56. }
  57. #ifdef OSG_USE_REF_PTR_IMPLICIT_OUTPUT_CONVERSION
  58. // implicit output conversion
  59. operator T*() const { return _ptr; }
  60. #else
  61. // comparison operators for ref_ptr.
  62. bool operator == (const ref_ptr& rp) const { return (_ptr==rp._ptr); }
  63. bool operator == (const T* ptr) const { return (_ptr==ptr); }
  64. friend bool operator == (const T* ptr, const ref_ptr& rp) { return (ptr==rp._ptr); }
  65. bool operator != (const ref_ptr& rp) const { return (_ptr!=rp._ptr); }
  66. bool operator != (const T* ptr) const { return (_ptr!=ptr); }
  67. friend bool operator != (const T* ptr, const ref_ptr& rp) { return (ptr!=rp._ptr); }
  68. bool operator < (const ref_ptr& rp) const { return (_ptr<rp._ptr); }
  69. // follows is an implementation of the "safe bool idiom", details can be found at:
  70. // http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool
  71. // http://lists.boost.org/Archives/boost/2003/09/52856.php
  72. private:
  73. typedef T* ref_ptr::*unspecified_bool_type;
  74. public:
  75. // safe bool conversion
  76. operator unspecified_bool_type() const { return valid()? &ref_ptr::_ptr : 0; }
  77. #endif
  78. T& operator*() const
  79. {
  80. #ifdef OSG_USE_REF_PTR_SAFE_DEREFERENCE
  81. if( !_ptr ) {
  82. // pointer is invalid, so throw an exception
  83. throw std::runtime_error(std::string("could not dereference invalid osg pointer ") + std::string(typeid(T).name()));
  84. }
  85. #endif
  86. return *_ptr;
  87. }
  88. T* operator->() const
  89. {
  90. #ifdef OSG_USE_REF_PTR_SAFE_DEREFERENCE
  91. if( !_ptr ) {
  92. // pointer is invalid, so throw an exception.
  93. throw std::runtime_error(std::string("could not call invalid osg pointer ") + std::string(typeid(T).name()));
  94. }
  95. #endif
  96. return _ptr;
  97. }
  98. T* get() const { return _ptr; }
  99. bool operator!() const { return _ptr==0; } // not required
  100. bool valid() const { return _ptr!=0; }
  101. /** release the pointer from ownership by this ref_ptr<>, decrementing the objects refencedCount() via unref_nodelete() to prevent the Object
  102. * object from being deleted even if the reference count goes to zero. Use when using a local ref_ptr<> to an Object that you want to return
  103. * from a function/method via a C pointer, whilst preventing the normal ref_ptr<> destructor from cleaning up the object. When using release()
  104. * you are implicitly expecting other code to take over management of the object, otherwise a memory leak will result. */
  105. T* release() { T* tmp=_ptr; if (_ptr) _ptr->unref_nodelete(); _ptr=0; return tmp; }
  106. void swap(ref_ptr& rp) { T* tmp=_ptr; _ptr=rp._ptr; rp._ptr=tmp; }
  107. private:
  108. template<class Other> void assign(const ref_ptr<Other>& rp)
  109. {
  110. if (_ptr==rp._ptr) return;
  111. T* tmp_ptr = _ptr;
  112. _ptr = rp._ptr;
  113. if (_ptr) _ptr->ref();
  114. // unref second to prevent any deletion of any object which might
  115. // be referenced by the other object. i.e rp is child of the
  116. // original _ptr.
  117. if (tmp_ptr) tmp_ptr->unref();
  118. }
  119. template<class Other> friend class ref_ptr;
  120. T* _ptr;
  121. };
  122. template<class T> inline
  123. void swap(ref_ptr<T>& rp1, ref_ptr<T>& rp2) { rp1.swap(rp2); }
  124. template<class T> inline
  125. T* get_pointer(const ref_ptr<T>& rp) { return rp.get(); }
  126. template<class T, class Y> inline
  127. ref_ptr<T> static_pointer_cast(const ref_ptr<Y>& rp) { return static_cast<T*>(rp.get()); }
  128. template<class T, class Y> inline
  129. ref_ptr<T> dynamic_pointer_cast(const ref_ptr<Y>& rp) { return dynamic_cast<T*>(rp.get()); }
  130. template<class T, class Y> inline
  131. ref_ptr<T> const_pointer_cast(const ref_ptr<Y>& rp) { return const_cast<T*>(rp.get()); }
  132. }
  133. #endif