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