Smart Pointers

copy_ptr.hpp

00001 #ifndef copy_ptr_H_HEADER_GUARD_
00002 #define copy_ptr_H_HEADER_GUARD_
00003 
00004 /*
00005 // copy_ptr class by David Maisonave (Axter) and Kai-Uwe Bux
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:
00017 The copy_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 copy_ptr, is to make it easier to create
00020 a container of abstract based objects.
00021 The copy_ptr does not share it's pointer, nor does it move it's pointer,
00022 and moreover, it's based on the idea of strict pointer ownership logic.
00023 The main difference between copy_ptr and other similar smart pointers
00024 is that the copy_ptr has a clone function pointer, which is used to create
00025 a copy of the derived object.  The clone function pointer is used in
00026 the copy_ptr copy constructor and in the assignment operator.
00027 
00028 The copy_ptr can also be used with sorted containers (std::map, std::set).
00029 When used with sorted containers, the base class must have an operator<() function. (See example code.)
00030 
00031 ****** For more detailed description and example usage see following links: *******
00032 Example Program:
00033 http://code.axter.com/clone_ptr_demo.zip
00034 Detail description:
00035 http://www.codeguru.com/Cpp/Cpp/algorithms/general/article.php/c10407
00036 
00037 See example program for example usage.
00038 
00039 */
00040 
00041 template < typename T, typename DT> T *  copy_ptr_ConstructAndDestruct_default_allocator_(const T*, bool, DT* , void*);
00042 template < typename T, typename D, class AX_TYPE> T *  copy_ptr_ConstructAndDestruct_(const T* , bool, D* , AX_TYPE*);
00043 
00049 template<typename T>
00050 class copy_ptr
00051 {
00052         typedef T * ( *clone_fct_Type ) (const T *, bool, void*, void*);//Last two values are not used (See note#1 at end of file)
00053         T* m_type;
00054         clone_fct_Type m_clone_fct;
00055 public:
00056         template<typename T_obj>
00057                 static  clone_fct_Type get_alloc_func(T_obj*)
00058         {
00059                 T * ( *tmp ) (const T *, bool, T_obj*, void*) = copy_ptr_ConstructAndDestruct_default_allocator_<T,T_obj>;
00060                 return (clone_fct_Type)tmp;
00061         }
00062         //copy_ptr will only clone type that is pass to the constructor
00063         template<typename T_obj>
00064         copy_ptr(T_obj* type):m_type(type), m_clone_fct(get_alloc_func(type))
00065         {
00066 #ifdef BOOST_ASSERT
00067                 BOOST_ASSERT(type != NULL);
00068                 BOOST_ASSERT(typeid(*type) == typeid(T_obj));
00069 #endif //BOOST_ASSERT
00070         }
00071         template<typename T_obj, class AX_TYPE>
00072         copy_ptr(T_obj* type, AX_TYPE&):m_type(type), m_clone_fct(NULL)
00073         {
00074 #ifdef BOOST_ASSERT
00075                 BOOST_ASSERT(type != NULL);
00076                 BOOST_ASSERT(typeid(*type) == typeid(T_obj));
00077 #endif //BOOST_ASSERT
00078                 T * ( *tmp ) ( const T *, bool, T_obj*, AX_TYPE*) = copy_ptr_ConstructAndDestruct_<T,T_obj, AX_TYPE>;
00079                 m_clone_fct = (clone_fct_Type)tmp;
00080         }
00081         //Destructor
00082         ~copy_ptr()throw(){if (m_type) m_type=m_clone_fct(m_type, false, NULL, NULL);}
00083         //Copy constructor
00084         copy_ptr(const copy_ptr& Src):m_type((Src.m_type)?Src.m_clone_fct(Src.m_type, true, NULL, NULL):NULL), m_clone_fct(Src.m_clone_fct){}
00085 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
00086         //Constructor for derived type copy_ptr<deriveT>
00087         template<class CompatibleDerivedT>      copy_ptr(const copy_ptr<CompatibleDerivedT>& Src):m_type(NULL), m_clone_fct(NULL){assign(Src);}
00088         //Constructor for cow_ptr or other compatible smart pointers
00089         template<class CompatibleSmartPtr>      copy_ptr(const CompatibleSmartPtr& Src):m_type(NULL), m_clone_fct(NULL){Src.make_clone(m_type, m_clone_fct);}
00090 #else
00091 #ifdef cow_ptr_H_HEADER_GUARD_
00092         copy_ptr(const cow_ptr<T>& Src):m_type(NULL), m_clone_fct(NULL){Src.make_clone(m_type, m_clone_fct);}
00093 #endif //cow_ptr_H_HEADER_GUARD_
00094 #endif //_MSC_VER != 1200
00095         //Assignment operator
00096         copy_ptr& operator=(const copy_ptr& Src){return assign(Src);}
00097         enum implement_default_object{eYes, eNo};
00098         //Default constructor needed for std::map
00099         copy_ptr(implement_default_object use_default_obj = eYes):m_type(NULL), m_clone_fct(NULL)
00100         {
00101                 if (use_default_obj == eYes)
00102                 {
00103                         copy_ptr<T> &defaultObj = GetSetDefaultObject();
00104                         if (defaultObj.m_type)
00105                         {
00106                                 m_type = defaultObj.m_clone_fct(defaultObj.m_type, true, NULL, NULL);
00107                                 m_clone_fct = defaultObj.m_clone_fct;
00108                         }
00109                 }
00110         }
00111         //For added safety, call SetDefaultObject to set default object before
00112         //using this class as the second type in a std::map
00113         static void SetDefaultObject(const copy_ptr<T>& NewValue){GetSetDefaultObject(&NewValue);}
00114 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
00115         //Assignment operator for smart pointer derived type copy_ptr<DerivedT>
00116         template<class CompatibleDerivedT>      copy_ptr& operator=(const copy_ptr<CompatibleDerivedT>& Src){return assign(Src);}
00117 #endif //_MSC_VER != 1200
00118         typedef T* pointer;
00119         typedef T& reference;
00120         bool operator! () const{
00121                 return m_type == 0;
00122         }
00123         template<typename T2>
00124         copy_ptr& equal(const T2& Src){
00125                 (*m_type) = (Src);
00126                 return *this;
00127         }
00128         inline T* operator->() const{return m_type;}
00129         inline T& operator*() const{return *m_type;}
00130 
00131         copy_ptr& operator+=(const copy_ptr& Src){
00132                 m_type->operator+=(*Src.m_type);
00133                 return *this;
00134         }
00135         template<typename T2>
00136         copy_ptr& operator+=(const T2& Src){
00137                 m_type->operator+=(Src);
00138                 return *this;
00139         }
00140         copy_ptr& operator+(const copy_ptr& Src){
00141                 m_type->operator+(*Src.m_type);
00142                 return *this;
00143         }
00144         copy_ptr& operator-=(const copy_ptr& Src){
00145                 m_type->operator-=(*Src.m_type);
00146                 return *this;
00147         }
00148         copy_ptr& operator-(const copy_ptr& Src){
00149                 m_type->operator-(*Src.m_type);
00150                 return *this;
00151         }
00152         const T* c_ptr()const{return  m_type;}
00153         const T& c_ref()const{return  *m_type;}
00154         T* get_ptr(){return m_type;}
00155         //Other Misc methods
00156         void swap(copy_ptr<T> & other)throw(){std::swap(m_type, other.m_type);std::swap(m_clone_fct, other.m_clone_fct);}
00157 
00158         //get_function_ptr needed for operator=(const copy_ptr<CompatibleDerivedT>&
00159         clone_fct_Type get_function_ptr()const{return m_clone_fct;}
00160 private:
00161         template<class CompatibleSmartPtr>
00162                 copy_ptr& assign(CompatibleSmartPtr& Src)
00163         {
00164                 if (m_type != (T*)Src.c_ptr()) //Cast needed for Borland compiler
00165                 {
00166                         if (m_type) m_clone_fct(m_type, false, NULL, NULL);
00167                         if (Src.c_ptr())
00168                                 m_type = Src.get_function_ptr()(Src.c_ptr(), true, NULL, NULL);
00169                         else m_type = NULL;
00170                         m_clone_fct = (clone_fct_Type)Src.get_function_ptr();
00171                 }
00172                 return *this;
00173         }
00174 
00175         static copy_ptr<T>& GetSetDefaultObject(const copy_ptr<T>* NewValue = NULL)
00176         {
00177                 static copy_ptr<T> DefaultObj(eNo);
00178                 if (NewValue && NewValue->m_type)
00179                         DefaultObj = *NewValue;
00180                 return DefaultObj;
00181         }
00182 };
00183 
00184 template<class T, class U> inline bool operator<(copy_ptr<T> const & a, copy_ptr<U> const & b){return (*a.c_ptr()) < (*b.c_ptr());}
00185 template<class T, class U> inline bool operator>(copy_ptr<T> const & a, copy_ptr<U> const & b){return (*a.c_ptr()) > (*b.c_ptr());}
00186 template<class T, class U> inline bool operator<=(copy_ptr<T> const & a, copy_ptr<U> const & b){return (*a.c_ptr()) <= (*b.c_ptr());}
00187 template<class T, class U> inline bool operator>=(copy_ptr<T> const & a, copy_ptr<U> const & b){return (*a.c_ptr()) >= (*b.c_ptr());}
00188 template<class T, class U> inline bool operator==(copy_ptr<T> const & a, copy_ptr<U> const & b){return (*a.c_ptr()) == (*b.c_ptr());}
00189 template<class T, class U> inline bool operator!=(copy_ptr<T> const & a, copy_ptr<U> const & b){return (*a.c_ptr()) != (*b.c_ptr());}
00190 
00191 #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
00192 // Resolve the ambiguity between our op!= and the one in rel_ops
00193 template<class T> inline bool operator!=(copy_ptr<T> const & a, copy_ptr<T> const & b){return (*a.c_ptr()) != (*b.c_ptr());}
00194 #endif
00195 
00196 /*
00197 Note#1:
00198 The ConstructAndDestruct functions have two extra arguments that are not used.  These arguments are not required at all in more compliant compilers
00199 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
00200 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
00201 are not needed.  Anything pass to these last two arguments will be discarded.
00202 */
00203 
00204 // The clone function: (Thanks to Kai-Uwe Bux)
00205 template < typename T, typename DT> T *  copy_ptr_ConstructAndDestruct_default_allocator_(const T *  ptr, bool bConstruct, DT* , void*) {
00206         if (bConstruct)
00207         {
00208                 DT* d = new DT(*static_cast<const DT*>(ptr));
00209 #ifdef BOOST_ASSERT
00210                 BOOST_ASSERT(typeid(*static_cast<const DT*>(ptr)) == typeid(*d));
00211 #endif //BOOST_ASSERT
00212                 return d;
00213         }
00214 #if !defined(_MSC_VER) || (_MSC_VER > 1200)
00215         delete ptr;
00216 #else
00217         delete const_cast<T*>(ptr); //For VC++ 6.0 bug which doesn't allow deletion of constant pointer
00218 #endif
00219         return NULL;
00220 } 
00221 
00222 template < typename T, typename D, class AX_TYPE> T *  copy_ptr_ConstructAndDestruct_(const T *  ptr, bool bConstruct, D* , AX_TYPE*) {
00223         D * Obj = static_cast<D*>( ptr );
00224         if (bConstruct)
00225         {
00226                 AX_TYPE alloc;
00227                 D* tmp_ptr = alloc.allocate(1, NULL);
00228                 alloc.construct(tmp_ptr, *(Obj));
00229 #ifdef BOOST_ASSERT
00230                 BOOST_ASSERT(typeid(*tmp_ptr) == typeid(*Obj));
00231 #endif //BOOST_ASSERT
00232                 return tmp_ptr;
00233         }
00234         AX_TYPE alloc;
00235         alloc.destroy(Obj);
00236         alloc.deallocate(Obj, 1);
00237         return NULL;
00238 } 
00239 
00240 
00241 #endif 
00242 

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