core/vil/vil_smart_ptr.h
Go to the documentation of this file.
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_