core/vbl/vbl_shared_pointer.h
Go to the documentation of this file.
00001 // This is core/vbl/vbl_shared_pointer.h
00002 #ifndef vbl_shared_pointer_h_
00003 #define vbl_shared_pointer_h_
00004 //:
00005 // \file
00006 // \brief Non-intrusive smart pointers
00007 // \author fsm
00008 //
00009 // \verbatim
00010 //  Modifications
00011 //   10 Sep. 2004 Peter Vanroose  Inlined all 1-line methods in class decl
00012 //   13 Feb. 2007 Amitha Perera   Change implementation to allow base class conversions.
00013 // \endverbatim
00014 
00015 #include <vcl_compiler.h>
00016 
00017 #define vbl_shared_pointer_zero(var) (var) = 0
00018 
00019 
00020 struct vbl_shared_pointer_data
00021 {
00022   int use_count; //!< number of shared_pointers using object.
00023   vbl_shared_pointer_data(int u) : use_count(u) { }
00024 };
00025 
00026 //: Non-intrusive smart pointers
00027 //
00028 // If your compiler supports member templates, these pointers will
00029 // also work with base classes and derived classes, so that they work
00030 // very much like raw pointers. If you do this, make sure your
00031 // destructors are virtual (as you'd need to do for raw pointers
00032 // anyway).
00033 template <class T>
00034 class vbl_shared_pointer
00035 {
00036  public:
00037   typedef T element_type;
00038   typedef vbl_shared_pointer<T> self;
00039 
00040   typedef vbl_shared_pointer_data data_t;
00041 
00042   vbl_shared_pointer() : pointer(0), count_data(0) { }
00043 
00044   explicit
00045   vbl_shared_pointer(T *p) {
00046     if (p) {
00047       pointer = p;
00048       count_data = new data_t(1);
00049     } else {
00050       pointer = 0;
00051       count_data = 0;
00052     }
00053   }
00054 
00055   vbl_shared_pointer(self const &that)
00056     : pointer( that.pointer ),
00057       count_data( that.count_data )
00058   {
00059     up_ref();
00060   }
00061 
00062 #if VCL_HAS_MEMBER_TEMPLATES
00063   template<class U> friend class vbl_shared_pointer;
00064 
00065   //: Construct using smart pointer to derived class.
00066   template <class U>
00067   vbl_shared_pointer( vbl_shared_pointer<U> const &that )
00068     : pointer( that.pointer ),
00069       count_data( that.count_data )
00070   {
00071     up_ref();
00072   }
00073 
00074   template <class U>
00075   self &operator=( vbl_shared_pointer<U> const &that) {
00076     that.up_ref();
00077     down_ref();
00078     pointer = that.pointer;
00079     count_data = that.count_data;
00080     return *this;
00081   }
00082 
00083 #endif
00084 
00085 #if 0
00086   // Remove these convenience methods because they conflict with the
00087   // base class conversion of the raw pointer. That is, we should be
00088   // able to do
00089   //    vbl_shared_pointer<base> p = new derived;
00090   // but these overloads prevent that.
00091 #if VCL_HAS_MEMBER_TEMPLATES
00092   // if T has a constructor T::T(3, "foo") then it's nice
00093   // to be able to say
00094   //   vbl_shared_pointer<T> sp(3, "foo");
00095   // instead of
00096   //   vbl_shared_pointer<T> sp = new T(3, "foo");
00097   template </*typename*/ class V1>
00098   explicit vbl_shared_pointer(V1 const &v1)
00099     : data(new data_t(new T(v1), 1)) { }
00100 
00101   template <class V1, class V2>
00102   explicit vbl_shared_pointer(V1 const &v1, V2 const &v2)
00103     : data(new data_t(new T(v1, v2), 1)) { }
00104 
00105   template <class V1, class V2, class V3>
00106   explicit vbl_shared_pointer(V1 const &v1, V2 const &v2, V3 const &v3)
00107     : data(new data_t(new T(v1, v2, v3), 1)) { }
00108 
00109   template <class V1, class V2, class V3, class V4>
00110   explicit vbl_shared_pointer(V1 const &v1, V2 const &v2, V3 const &v3, V4 const &v4)
00111     : data(new data_t(new T(v1, v2, v3, v4), 1)) { }
00112 #endif
00113 #endif
00114 
00115   self &operator=(self const &that) {
00116     that.up_ref();
00117     down_ref();
00118     pointer = that.pointer;
00119     count_data = that.count_data;
00120     return *this;
00121   }
00122 
00123   ~vbl_shared_pointer() {
00124     down_ref();
00125   }
00126 
00127  private:
00128   VCL_SAFE_BOOL_DEFINE;
00129  public:
00130   // conversion to bool
00131   operator safe_bool () const
00132     { return (pointer != 0)? VCL_SAFE_BOOL_TRUE : 0; }
00133 
00134   // inverse conversion to bool
00135   bool operator!() const
00136     { return (pointer != 0)? false : true; }
00137 
00138   // conversion to pointer
00139 #if !defined VBL_SHARED_POINTER_OF_NON_COMPOUND // Get rid of warning with vbl_shared_pointer<int>
00140       // VCL_DO_NOT_INSTANTIATE can't be used instead because the declaration of
00141       // the method that causes the problem, not the instantiation.
00142   T const *operator->() const { return as_pointer(); }
00143   T       *operator->() { return as_pointer(); }
00144 #endif
00145 
00146   // conversion to T
00147   T const &operator*() const { return *as_pointer(); }
00148   T       &operator*() { return *as_pointer(); }
00149 
00150   // relational
00151   bool operator!=(self const &that) const { return pointer != that.pointer; }
00152   bool operator==(self const &that) const { return pointer == that.pointer; }
00153   bool operator< (self const &that) const { return pointer <  that.pointer; }
00154 
00155   // use these if you like, but at your own risk.
00156   T *as_pointer() const {
00157     return pointer;
00158   }
00159   void up_ref() const {
00160     if (count_data)
00161       ++ count_data->use_count;
00162   }
00163   void down_ref() const {
00164     if (count_data && (-- count_data->use_count == 0)) {
00165       delete pointer;
00166       delete count_data;
00167     }
00168   }
00169  private:
00170   T *pointer;    //!< pointer to object.
00171   data_t *count_data;
00172 };
00173 
00174 #define VBL_SHARED_POINTER_INSTANTIATE(T) // template class vbl_shared_pointer<T >
00175 
00176 #endif // vbl_shared_pointer_h_