Smart Pointers

cow_ptr.hpp

00001 #ifndef cow_ptr_H_HEADER_GUARD_
00002 #define cow_ptr_H_HEADER_GUARD_
00003 
00004 /*
00005 // cow_ptr class by David Maisonave (Axter)
00006 // Copyright (C) 2005
00007 // David Maisonave (Axter) (609-345-1007) (www.axter.com)
00008 //
00009 // Permission to use, copy, modify, distribute and sell this software
00010 // and its documentation for any purpose is hereby granted without fee,
00011 // provided that the above copyright notice appear in all copies and
00012 // that both that copyright notice and this permission notice appear
00013 // in supporting documentation.  David Maisonave (Axter) makes no representations
00014 // about the suitability of this software for any purpose.
00015 // It is provided "as is" without express or implied warranty.
00016 Description: COW = Copy On Write
00017 The cow_ptr class is a smart pointer class that can be used
00018 with an STL container to create a container of smart pointers.
00019 The main purpose of the cow_ptr, is to make it easier to create
00020 a container of abstract based objects with a smart pointer that has
00021 lazy construction logic.
00022 The cow_ptr will share the pointer until one of the shared objects tries
00023 to access the non-constant pointer.  At that point, the object is cloned,
00024 and it releases the reference count to the original pointer.
00025 The main difference between cow_ptr and other similar smart pointers
00026 is that the cow_ptr has a clone function pointer, which is used to create
00027 a copy of the derived object.  The clone function pointer is used in
00028 the cow_ptr copy constructor and in the assignment operator.
00029 
00030 The cow_ptr can also be used with sorted containers (std::map, std::set).
00031 When used with sorted containers, the base class must have an operator<() function. (See example code.)
00032 
00033 ****** For more detailed description and example usage see following links: *******
00034 Example Program:
00035 http://code.axter.com/clone_ptr_demo.zip
00036 
00037 See example program for example usage.
00038 
00039 */
00040 
00041 #include <algorithm>
00042 
00043 // The clone function: (Thanks to Kai-Uwe Bux)
00044 template < typename T, typename DT> T *  cow_ptr_ConstructAndDestruct_default_allocator_(T*, bool, DT* , void*);
00045 
00050 template<typename T>
00051 class cow_ptr
00052 {
00053         typedef T * ( *clone_fct_Type ) (const T *, bool, void*, void*);//Last two values are not used (See note#1 at end of file)
00054         struct ref_link
00055         {
00056                 ref_link():m_back(NULL), m_front(NULL){}
00057                 ref_link *m_back;
00058                 ref_link *m_front;
00059         private:  //Disallow copy constructor and assignment op
00060                 ref_link(const ref_link&);
00061                 ref_link& operator=(const ref_link&);
00062         };
00063         mutable ref_link m_ref_link;
00064         T* m_type;
00065         clone_fct_Type m_clone_fct;
00066 public:
00067         //cow_ptr will only clone type that is pass to the constructor
00068         template<typename T_obj>
00069                 cow_ptr(T_obj* type): m_type(type), m_clone_fct(get_alloc_func(type))
00070         {
00071 #ifdef BOOST_ASSERT
00072                 BOOST_ASSERT(type != NULL);
00073                 BOOST_ASSERT(typeid(*type) == typeid(T_obj));
00074 #endif //BOOST_ASSERT
00075         }
00076         //Destructor
00077         ~cow_ptr() throw(){release();}
00078         //Copy constructor
00079         cow_ptr(const cow_ptr& Src):m_type(Src.m_type), m_clone_fct(Src.m_clone_fct){insert_link(&Src.m_ref_link);}
00080 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
00081         //Constructor for smart pointer derived type cow_ptr<DerivedT>
00082         template<class CompatibleDerivedT>
00083                 cow_ptr(const cow_ptr<CompatibleDerivedT>& Src):m_type(NULL), m_clone_fct(NULL)
00084         {//No clean way to do this via COW, so just clone it
00085                 Src.make_clone(m_type, m_clone_fct);
00086         }
00087         template<class CompatibleDerivedT>
00088                 cow_ptr& operator=(const cow_ptr<CompatibleDerivedT>& Src)
00089         {//No clean way to do this via COW, so just clone it
00090                 release();
00091                 Src.make_clone(m_type, m_clone_fct);
00092                 return *this;
00093         }
00094 #endif //_MSC_VER != 1200
00095         //Assignment operator
00096         cow_ptr& operator=(const cow_ptr& Src){return assign(Src);}
00097         enum implement_default_object{eYes, eNo};
00098         //Default constructor needed for std::map
00099         cow_ptr(implement_default_object use_default_obj = eYes):m_type(NULL), m_clone_fct(NULL)
00100         {
00101                 if (use_default_obj == eYes)
00102                         assign(GetSetDefaultObject());
00103         }
00104         //For added safety, call SetDefaultObject to set default object before
00105         //using this class as the second type in a std::map
00106         static void SetDefaultObject(const cow_ptr<T>& NewValue){GetSetDefaultObject(&NewValue);}
00107         typedef T* pointer;
00108         typedef T& reference;
00109         bool operator! () const{return c_ptr() == 0;}
00110         template<class T2>
00111                 cow_ptr& equal(const T2& Src){
00112                 (*get_ptr()) = (Src);
00113                 return *this;
00114         }
00115         //Operators that will force exclusive pointer
00116         inline T* operator->() {return get_ptr();}
00117         inline T& operator*() {return *get_ptr();}
00118         inline const T* operator->()const {return m_type;}
00119         inline const T& operator*() const {return *m_type;}
00120         cow_ptr& operator+=(const cow_ptr& Src){
00121                 get_ptr()->operator+=(*Src.c_ptr());
00122                 return *this;
00123         }
00124         template<class T2>
00125         cow_ptr& operator+=(const T2& Src){
00126                 get_ptr()->operator+=(Src);
00127                 return *this;
00128         }
00129         cow_ptr& operator+(const cow_ptr& Src){
00130                 get_ptr()->operator+(*Src.c_ptr());
00131                 return *this;
00132         }
00133         cow_ptr& operator-=(const cow_ptr& Src){
00134                 get_ptr()->operator-=(*Src.c_ptr());
00135                 return *this;
00136         }
00137         cow_ptr& operator-(const cow_ptr& Src){
00138                 get_ptr()->operator-(*Src.c_ptr());
00139                 return *this;
00140         }
00141         clone_fct_Type get_function_ptr()const{return m_clone_fct;}
00142         T* get_ptr() //get exclusive pointer
00143         {
00144                 if (is_ref_linked())
00145                 {
00146                         T* tmp = m_clone_fct(m_type, true, NULL, NULL);
00147                         release();
00148                         m_type = tmp;
00149                 }
00150                 return m_type;
00151         }
00152         inline const T* c_ptr()const{return  m_type;}
00153         inline const T& c_ref()const{return  *m_type;}
00154         //Other Misc methods
00155         void swap(cow_ptr<T> & other)throw(){std::swap(m_ref_link, other.m_ref_link);std::swap(m_type, other.m_type);std::swap(m_clone_fct, other.m_clone_fct);}
00156         //Needed for operator=(const cow_ptr<CompatibleDerivedT>& 
00157         bool is_ref_linked()const{return (m_ref_link.m_back || m_ref_link.m_front);}
00158         //Allows cloning
00159         template<class PT, class FPT>   void make_clone(PT*& ptr, FPT& func_ptr) const
00160         {
00161                 if (m_type)
00162                 {
00163                         ptr = m_clone_fct(m_type, true, NULL, NULL);
00164                         func_ptr = (FPT)m_clone_fct;
00165                 }
00166                 else
00167                         ptr = NULL;
00168         }
00169 private:
00170         template<typename T_obj>
00171                 static  clone_fct_Type get_alloc_func(T_obj*)
00172         {
00173                 T * ( *tmp ) (T *, bool, T_obj*, void*) = cow_ptr_ConstructAndDestruct_default_allocator_<T,T_obj>;
00174                 return (clone_fct_Type)tmp;
00175         }
00176         void release() throw()
00177         {
00178                 if (!is_ref_linked()){
00179                         m_clone_fct(m_type, false, NULL, NULL);
00180                         m_type = NULL;
00181                 }
00182                 else
00183                 {
00184                         pop_link();
00185                 }
00186         }
00187         void pop_link()
00188         {
00189                 if (m_ref_link.m_back)
00190                 {
00191                         m_ref_link.m_back->m_front = m_ref_link.m_front;
00192                 }
00193                 if (m_ref_link.m_front)
00194                 {
00195                         m_ref_link.m_front->m_back = m_ref_link.m_back;
00196                 }
00197                 m_ref_link.m_front = NULL;
00198                 m_ref_link.m_back = NULL;
00199         }
00200         void insert_link(ref_link *Target)
00201         {
00202                 m_ref_link.m_back = Target;
00203                 m_ref_link.m_front = Target->m_front;
00204                 if (m_ref_link.m_front)
00205                 {
00206                         m_ref_link.m_front->m_back = &m_ref_link;
00207                 }
00208                 if (m_ref_link.m_back)
00209                 {
00210                         m_ref_link.m_back->m_front = &m_ref_link;
00211                 }
00212         }
00213         template<class CompatibleSmartPtr>
00214                 cow_ptr& assign(CompatibleSmartPtr& Src)
00215         {
00216                 if (!m_type || Src.is_ref_linked() || m_type != Src.c_ptr())
00217                 {
00218                         release();
00219                         m_type = Src.m_type;
00220                         m_clone_fct = Src.m_clone_fct;
00221                         insert_link(&Src.m_ref_link);
00222                 }
00223                 return *this;
00224         }
00225         static cow_ptr<T>& GetSetDefaultObject(const cow_ptr<T>* NewValue = NULL)
00226         {
00227                 static cow_ptr<T> DefaultObj(eNo);
00228                 if (NewValue && NewValue->m_type)
00229                         DefaultObj = *NewValue;
00230                 return DefaultObj;
00231         }
00232 };
00233 
00234 //Operators that can work with the shared pointer
00235 template<class T, class U> bool operator<(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) < (*b.c_ptr());}
00236 template<class T, class U> bool operator>(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) > (*b.c_ptr());}
00237 template<class T, class U> bool operator<=(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) <= (*b.c_ptr());}
00238 template<class T, class U> bool operator>=(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) >= (*b.c_ptr());}
00239 template<class T, class U> bool operator==(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) == (*b.c_ptr());}
00240 template<class T, class U> bool operator!=(cow_ptr<T> const & a, cow_ptr<U> const & b){return (*a.c_ptr()) != (*b.c_ptr());}
00241 
00242 #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
00243 // Resolve the ambiguity between our op!= and the one in rel_ops
00244 template<class T> bool operator!=(cow_ptr<T> const & a, cow_ptr<T> const & b){return (*a.c_ptr()) != (*b.c_ptr());}
00245 #endif
00246 
00247 
00248 /*
00249 Note#1:
00250 The ConstructAndDestruct functions have two extra arguments that are not used.  These arguments are not required at all in more compliant compilers
00251 like VC++ 7.x and GNU 3.x.  However, for none compliant (pre-standard) compilers like VC++ 6.0 and BCC55, the extra argument declaration is required
00252 so as to be able to fully qualify the function template type.  The argument declarations are needed for these compilers, but the actual argument variables
00253 are not needed.  Anything pass to these last two arguments will be discarded.
00254 */
00255 
00256 // The clone function: (Thanks to Kai-Uwe Bux)
00257 template < typename T, typename DT> T *  cow_ptr_ConstructAndDestruct_default_allocator_(T *  ptr, bool bConstruct, DT* , void*) {
00258         if (bConstruct){return new DT(*static_cast<const DT*>(ptr));} //Should add assert like the following  assert(typeid(*tmp_ptr) == typeid(*Obj));
00259         delete const_cast<T*>(ptr); //This cast is needed for VC++ 6.0
00260         return NULL;
00261 } 
00262 
00263 
00264 #endif 
00265 

Generated on Wed Mar 29 21:58:58 2006 for Smart Pointers by  doxygen 1.4.6.Axter [Axter-Extended-Version]