00001 // This is core/vil/vil_smart_ptr.h 00002 #ifndef vil_smart_ptr_h_ 00003 #define vil_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 // 2002.9.20 Ian Scott Copied into vil1, renamed and simplified. 00019 // \endverbatim 00020 00021 #include <vcl_iosfwd.h> 00022 00023 //: A templated smart pointer class 00024 // This class requires that the class being templated over has 00025 // the following signatures (methods) : 00026 // \code 00027 // void T::ref(); 00028 // void T::unref(); 00029 // \endcode 00030 // 00031 // 00032 // See also vbl_ref_count 00033 template <class T> 00034 class vil_smart_ptr 00035 { 00036 VCL_SAFE_BOOL_DEFINE; 00037 public: 00038 vil_smart_ptr () 00039 : ptr_(0) { } 00040 00041 vil_smart_ptr (vil_smart_ptr<T> const &p) 00042 : ptr_(p.as_pointer()) { if (ptr_) ref(ptr_); } 00043 00044 vil_smart_ptr (T *p) 00045 : ptr_(p) { if (ptr_) ref(ptr_); } 00046 00047 ~vil_smart_ptr () 00048 { 00049 // the strange order of events in this function is to avoid 00050 // heap corruption if unref() causes *this to be deleted. 00051 T *old_ptr = ptr_; 00052 ptr_ = 0; 00053 if (old_ptr) 00054 unref(old_ptr); 00055 } 00056 00057 //: Assignment 00058 vil_smart_ptr<T> &operator = (vil_smart_ptr<T> const &r) 00059 { 00060 return operator=(r.as_pointer()); 00061 } 00062 00063 vil_smart_ptr<T> &operator = (T *r) 00064 { 00065 if (ptr_ != r) 00066 { 00067 // If there are circular references, calling unref() may 00068 // cause *this to be destroyed and so assigning to 'ptr_' 00069 // would be ill-formed and could cause heap corruption. 00070 // Hence perform the unref() only at the very end. 00071 T *old_ptr = ptr_; 00072 ptr_ = r; 00073 00074 if (ptr_) 00075 ref(ptr_); 00076 00077 // *this might get deleted now, but that's ok. 00078 if (old_ptr) 00079 unref(old_ptr); 00080 } 00081 return *this; 00082 } 00083 00084 //: Cast to bool 00085 operator safe_bool () const 00086 { return (ptr_ != (T*)0)? VCL_SAFE_BOOL_TRUE : 0; } 00087 00088 //: Inverse bool 00089 bool operator!() const 00090 { return (ptr_ != (T*)0)? false : true; } 00091 00092 //: Dereferencing the pointer 00093 T &operator * () const { return *ptr_; } 00094 00095 //: These methods all return the raw/dumb pointer. 00096 T *operator -> () const { return ptr_; } 00097 00098 //: These methods all return the raw/dumb pointer. 00099 T *ptr () const { return ptr_; } 00100 00101 //: These methods all return the raw/dumb pointer. 00102 // 00103 // WARNING : Do not add an automatic cast to T*. 00104 // This is intrinsically incorrect as you loose the smartness! 00105 // In cases where you really need the pointer, it is better 00106 // to be explicit about it and use one of the methods. 00107 T *as_pointer () const { return ptr_; } 00108 00109 // Relational operators. 00110 //There's no need for casts to void* or any other pointer type than T* here. 00111 00112 //: Do a shallow equality 00113 // Do they point to the same object. 00114 bool operator==(T const *p) const { return ptr_ == p; } 00115 00116 //: Do a shallow inequality 00117 // Do the smart pointers not point to the same object. 00118 bool operator!=(T const *p) const { return ptr_ != p; } 00119 00120 //: Do a shallow equality 00121 // Do they point to the same object. 00122 bool operator==(vil_smart_ptr<T>const&p)const{return ptr_ == p.as_pointer();} 00123 00124 //: Do a shallow inequality 00125 // Do the smart pointers not point to the same object. 00126 bool operator!=(vil_smart_ptr<T>const&p)const{return ptr_ != p.as_pointer();} 00127 bool operator< (vil_smart_ptr<T>const&p)const{return ptr_ < p.as_pointer();} 00128 bool operator> (vil_smart_ptr<T>const&p)const{return ptr_ > p.as_pointer();} 00129 bool operator<=(vil_smart_ptr<T>const&p)const{return ptr_ <= p.as_pointer();} 00130 bool operator>=(vil_smart_ptr<T>const&p)const{return ptr_ >= p.as_pointer();} 00131 00132 private: 00133 // These two methods should not be inlined as they call T's ref() 00134 // and unref() or are specializations. The big gain from that is 00135 // that vil_smart_ptr<T> can be forward declared even if T is still 00136 // an incomplete type. 00137 static void ref (T *p); 00138 static void unref(T *p); 00139 00140 //: Pointer to object, or 0. 00141 T *ptr_; 00142 }; 00143 00144 00145 //: Comparison of pointer with smart-pointer (cannot be a member function) 00146 template <class T> 00147 inline bool operator== (T const* p, vil_smart_ptr<T> const& a) 00148 { 00149 return a.as_pointer() == p; 00150 } 00151 00152 template <class T> 00153 inline bool operator!= (T const* p, vil_smart_ptr<T> const& a) 00154 { 00155 return a.as_pointer() != p; 00156 } 00157 00158 // Sunpro and GCC need a vcl_ostream operator. It need not be inline 00159 // because if you're about to make a system call you can afford the 00160 // cost of a function call. 00161 template <class T> 00162 vcl_ostream& operator<< (vcl_ostream&, vil_smart_ptr<T> const&); 00163 00164 #define VIL_SMART_PTR_INSTANTIATE(T) \ 00165 extern "please include vil/vil_smart_ptr.txx instead" 00166 00167 #endif // vil_smart_ptr_h_