00001 // This is core/vbl/vbl_smart_ptr.h 00002 #ifndef vbl_smart_ptr_h_ 00003 #define vbl_smart_ptr_h_ 00004 //: 00005 // \file 00006 // \brief Contains a templated smart pointer class 00007 // \author Richard Hartley (original Macro version), 00008 // William A. Hoffman (current templated version) 00009 // 00010 // \verbatim 00011 // Modifications 00012 // 2000.05.15 François BERTEL Added some missing <T> 00013 // 2000.05.16 Peter Vanroose Operators > < >= <= made const 00014 // 2000.09.13 fsm Added rationale for unprotect(). 00015 // PDA (Manchester) 23/03/2001: Tidied up the documentation 00016 // Peter Vanroose 27/05/2001: Corrected the documentation 00017 // Feb.2002 - Peter Vanroose - brief doxygen comment placed on single line 00018 // \endverbatim 00019 00020 #include <vcl_iosfwd.h> 00021 00022 //: A templated smart pointer class 00023 // This class requires that the class being templated over has 00024 // the following signatures (methods) : 00025 // \code 00026 // void T::ref(); 00027 // void T::unref(); 00028 // \endcode 00029 // 00030 // By default, the vbl_smart_ptr<T> will ref() the object given 00031 // to it upon construction and unref() it upon destruction. In 00032 // some cases, however, it is useful to cause an unref() immediately 00033 // and to avoid an unref() in the constructor. For example, in the 00034 // cyclic data structure 00035 // \code 00036 // start -> A -> B -> C -> D -> E 00037 // ^ | 00038 // | | 00039 // +-------------------+ 00040 // \endcode 00041 // 00042 // The refcounts on A, B, C, D, E are 2, 1, 1, 1, 1 so when 'start' 00043 // goes out of scope, the refcount will be 1, 1, 1, 1, 1 and therefore 00044 // the ring never gets deleted. Calling unprotect() on 'E' solves this 00045 // as it effectively transfers ownership of 'A' from 'E' to 'start'. 00046 // 00047 // Although unprotect() can be handy, it should be used with care. It 00048 // can sometimes (but not always) be avoided by assigning 0 (null pointer) 00049 // to one of the nodes in the ring. 00050 // 00051 // See also vbl_ref_count 00052 template <class T> 00053 class vbl_smart_ptr 00054 { 00055 //: The protected flag says whether or not the object held will be unref()fed when the smart pointer goes out of scope. 00056 bool protected_; 00057 00058 //: Pointer to object, or 0. 00059 T *ptr_; 00060 00061 VCL_SAFE_BOOL_DEFINE; 00062 public: 00063 vbl_smart_ptr () 00064 : protected_(true), ptr_(0) { } 00065 00066 vbl_smart_ptr (vbl_smart_ptr<T> const &p) 00067 : protected_(true), ptr_(p.as_pointer()) { if (ptr_) ref(ptr_); } 00068 00069 vbl_smart_ptr (T *p) 00070 : protected_(true), ptr_(p) { if (ptr_) ref(ptr_); } 00071 00072 ~vbl_smart_ptr () 00073 { 00074 // the strange order of events in this function is to avoid 00075 // heap corruption if unref() causes *this to be deleted. 00076 if (protected_) 00077 { 00078 T *old_ptr = ptr_; 00079 ptr_ = 0; 00080 if (old_ptr) 00081 unref(old_ptr); 00082 } 00083 else 00084 ptr_ = 0; 00085 } 00086 00087 //: Assignment 00088 vbl_smart_ptr<T> &operator = (vbl_smart_ptr<T> const &r) 00089 { 00090 return operator=(r.as_pointer()); 00091 } 00092 00093 vbl_smart_ptr<T> &operator = (T *r) 00094 { 00095 if (ptr_ != r) 00096 { 00097 // If there are circular references, calling unref() may 00098 // cause *this to be destroyed and so assigning to 'ptr_' 00099 // would be ill-formed and could cause heap corruption. 00100 // Hence perform the unref() only at the very end. 00101 T *old_ptr = ptr_; 00102 ptr_ = r; 00103 00104 if (ptr_) 00105 ref(ptr_); 00106 00107 // *this might get deleted now, but that's ok. 00108 if (old_ptr && protected_) 00109 unref(old_ptr); 00110 } 00111 protected_ = true; 00112 return *this; 00113 } 00114 00115 //: Cast to bool 00116 operator safe_bool () const { return ptr_? VCL_SAFE_BOOL_TRUE : 0; } 00117 00118 //: Inverse boolean value 00119 bool operator!() const { return ptr_? false : true; } 00120 00121 //: Dereferencing the pointer 00122 T &operator * () const { return *ptr_; } 00123 00124 //: These methods all return the raw/dumb pointer. 00125 T *operator -> () const { return ptr_; } 00126 00127 //: These methods all return the raw/dumb pointer. 00128 T *ptr () const { return ptr_; } 00129 00130 //: These methods all return the raw/dumb pointer. 00131 // 00132 // WARNING : Do not add an automatic cast to T*. 00133 // This is intrinsically incorrect as you loose the smartness! 00134 // In cases where you really need the pointer, it is better 00135 // to be explicit about it and use one of the methods. 00136 T *as_pointer () const { return ptr_; } 00137 00138 //: Used for breaking circular references (see above). 00139 void unprotect() { 00140 if (protected_ && ptr_) 00141 unref(ptr_); 00142 protected_ = false; 00143 } 00144 00145 //: Is this smart pointer responsible for the object being pointed to 00146 // If this value is false, the object does not have to save it. 00147 bool is_protected() const { return protected_; } 00148 00149 #if 0 // no longer needed 00150 //: If a T_ref is converted to a pointer then back to a T_ref, you'll need to call this 00151 void protect() 00152 { 00153 if (!protected_ && ptr_) 00154 ref(ptr_); 00155 protected_ = true; 00156 } 00157 #endif 00158 00159 // Relational operators. 00160 //There's no need for casts to void* or any other pointer type than T* here. 00161 00162 //: Do a shallow equality 00163 // Do they point to the same object. 00164 bool operator==(T const *p) const { return ptr_ == p; } 00165 00166 //: Do a shallow inequality 00167 // Do the smart pointers not point to the same object. 00168 bool operator!=(T const *p) const { return ptr_ != p; } 00169 00170 //: Do a shallow equality 00171 // Do they point to the same object. 00172 bool operator==(vbl_smart_ptr<T>const&p)const{return ptr_ == p.as_pointer();} 00173 00174 //: Do a shallow inequality 00175 // Do the smart pointers not point to the same object. 00176 bool operator!=(vbl_smart_ptr<T>const&p)const{return ptr_ != p.as_pointer();} 00177 bool operator< (vbl_smart_ptr<T>const&p)const{return ptr_ < p.as_pointer();} 00178 bool operator> (vbl_smart_ptr<T>const&p)const{return ptr_ > p.as_pointer();} 00179 bool operator<=(vbl_smart_ptr<T>const&p)const{return ptr_ <= p.as_pointer();} 00180 bool operator>=(vbl_smart_ptr<T>const&p)const{return ptr_ >= p.as_pointer();} 00181 00182 private: 00183 // These two methods should not be inlined as they call T's ref() 00184 // and unref() or are specializations. The big gain from that is 00185 // that vbl_smart_ptr<T> can be forward declared even if T is still 00186 // an incomplete type. 00187 static void ref (T *p); 00188 static void unref(T *p); 00189 }; 00190 00191 00192 //: Comparison of pointer with smart-pointer (cannot be a member function) 00193 template <class T> 00194 inline bool operator== (T const* p, vbl_smart_ptr<T> const& a) 00195 { 00196 return a.as_pointer() == p; 00197 } 00198 00199 template <class T> 00200 inline bool operator!= (T const* p, vbl_smart_ptr<T> const& a) 00201 { 00202 return a.as_pointer() != p; 00203 } 00204 00205 // Sunpro and GCC need a vcl_ostream operator. It need not be inline 00206 // because if you're about to make a system call you can afford the 00207 // cost of a function call. 00208 template <class T> 00209 vcl_ostream& operator<< (vcl_ostream&, vbl_smart_ptr<T> const&); 00210 00211 #define VBL_SMART_PTR_INSTANTIATE(T) \ 00212 extern "please include vbl/vbl_smart_ptr.txx instead" 00213 00214 #endif // vbl_smart_ptr_h_