#ifndef copy_ptr_H_HEADER_GUARD_ #define copy_ptr_H_HEADER_GUARD_ /* // copy_ptr class by David Maisonave (Axter) and Kai-Uwe Bux // Copyright (C) 2005 // David Maisonave (Axter) (609-345-1007) (www.axter.com) // // Permission to use, copy, modify, distribute and sell this software // and its documentation for any purpose is hereby granted without fee, // provided that the above copyright notice appear in all copies and // that both that copyright notice and this permission notice appear // in supporting documentation. David Maisonave (Axter) makes no representations // about the suitability of this software for any purpose. // It is provided "as is" without express or implied warranty. Description: The copy_ptr class is a smart pointer class that can be used with an STL container to create a container of smart pointers. The main purpose of the copy_ptr, is to make it easier to create a container of abstract based objects. The copy_ptr does not share it's pointer, nor does it move it's pointer, and moreover, it's based on the idea of strict pointer ownership logic. The main difference between copy_ptr and other similar smart pointers is that the copy_ptr has a clone function pointer, which is used to create a copy of the derived object. The clone function pointer is used in the copy_ptr copy constructor and in the assignment operator. The copy_ptr can also be used with sorted containers (std::map, std::set). When used with sorted containers, the base class must have an operator<() function. (See example code.) ****** For more detailed description and example usage see following links: ******* Example Program: http://code.axter.com/clone_ptr_demo.zip Detail description: http://www.codeguru.com/Cpp/Cpp/algorithms/general/article.php/c10407 See example program for example usage. */ template < typename T, typename DT> T * copy_ptr_ConstructAndDestruct_default_allocator_(const T*, bool, DT* , void*); template < typename T, typename D, class AX_TYPE> T * copy_ptr_ConstructAndDestruct_(const T* , bool, D* , AX_TYPE*); template class copy_ptr { typedef T * ( *clone_fct_Type ) (const T *, bool, void*, void*);//Last two values are not used (See note#1 at end of file) T* m_type; clone_fct_Type m_clone_fct; public: template static clone_fct_Type get_alloc_func(T_obj*) { T * ( *tmp ) (const T *, bool, T_obj*, void*) = copy_ptr_ConstructAndDestruct_default_allocator_; return (clone_fct_Type)tmp; } //copy_ptr will only clone type that is pass to the constructor template copy_ptr(T_obj* type):m_type(type), m_clone_fct(get_alloc_func(type)) { #ifdef BOOST_ASSERT BOOST_ASSERT(type != NULL); BOOST_ASSERT(typeid(*type) == typeid(T_obj)); #endif //BOOST_ASSERT } template copy_ptr(T_obj* type, AX_TYPE&):m_type(type), m_clone_fct(NULL) { #ifdef BOOST_ASSERT BOOST_ASSERT(type != NULL); BOOST_ASSERT(typeid(*type) == typeid(T_obj)); #endif //BOOST_ASSERT T * ( *tmp ) ( const T *, bool, T_obj*, AX_TYPE*) = copy_ptr_ConstructAndDestruct_; m_clone_fct = (clone_fct_Type)tmp; } //Destructor ~copy_ptr()throw(){if (m_type) m_type=m_clone_fct(m_type, false, NULL, NULL);} //Copy constructor 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){} #if !defined(_MSC_VER) || (_MSC_VER > 1200) //Constructor for derived type copy_ptr template copy_ptr(const copy_ptr& Src):m_type(NULL), m_clone_fct(NULL){assign(Src);} //Constructor for cow_ptr or other compatible smart pointers template copy_ptr(const CompatibleSmartPtr& Src):m_type(NULL), m_clone_fct(NULL){Src.make_clone(m_type, m_clone_fct);} #else #ifdef cow_ptr_H_HEADER_GUARD_ copy_ptr(const cow_ptr& Src):m_type(NULL), m_clone_fct(NULL){Src.make_clone(m_type, m_clone_fct);} #endif //cow_ptr_H_HEADER_GUARD_ #endif //_MSC_VER != 1200 //Assignment operator copy_ptr& operator=(const copy_ptr& Src){return assign(Src);} enum implement_default_object{eYes, eNo}; //Default constructor needed for std::map copy_ptr(implement_default_object use_default_obj = eYes):m_type(NULL), m_clone_fct(NULL) { if (use_default_obj == eYes) { copy_ptr &defaultObj = GetSetDefaultObject(); if (defaultObj.m_type) { m_type = defaultObj.m_clone_fct(defaultObj.m_type, true, NULL, NULL); m_clone_fct = defaultObj.m_clone_fct; } } } //For added safety, call SetDefaultObject to set default object before //using this class as the second type in a std::map static void SetDefaultObject(const copy_ptr& NewValue){GetSetDefaultObject(&NewValue);} #if !defined(_MSC_VER) || (_MSC_VER > 1200) //Assignment operator for smart pointer derived type copy_ptr template copy_ptr& operator=(const copy_ptr& Src){return assign(Src);} #endif //_MSC_VER != 1200 typedef T* pointer; typedef T& reference; bool operator! () const{ return m_type == 0; } template copy_ptr& equal(const T2& Src){ (*m_type) = (Src); return *this; } inline T* operator->() const{return m_type;} inline T& operator*() const{return *m_type;} copy_ptr& operator+=(const copy_ptr& Src){ m_type->operator+=(*Src.m_type); return *this; } template copy_ptr& operator+=(const T2& Src){ m_type->operator+=(Src); return *this; } copy_ptr& operator+(const copy_ptr& Src){ m_type->operator+(*Src.m_type); return *this; } copy_ptr& operator-=(const copy_ptr& Src){ m_type->operator-=(*Src.m_type); return *this; } copy_ptr& operator-(const copy_ptr& Src){ m_type->operator-(*Src.m_type); return *this; } const T* c_ptr()const{return m_type;} const T& c_ref()const{return *m_type;} T* get_ptr(){return m_type;} //Other Misc methods void swap(copy_ptr & other)throw(){std::swap(m_type, other.m_type);std::swap(m_clone_fct, other.m_clone_fct);} //get_function_ptr needed for operator=(const copy_ptr& clone_fct_Type get_function_ptr()const{return m_clone_fct;} private: template copy_ptr& assign(CompatibleSmartPtr& Src) { if (m_type != (T*)Src.c_ptr()) //Cast needed for Borland compiler { if (m_type) m_clone_fct(m_type, false, NULL, NULL); if (Src.c_ptr()) m_type = Src.get_function_ptr()(Src.c_ptr(), true, NULL, NULL); else m_type = NULL; m_clone_fct = (clone_fct_Type)Src.get_function_ptr(); } return *this; } static copy_ptr& GetSetDefaultObject(const copy_ptr* NewValue = NULL) { static copy_ptr DefaultObj(eNo); if (NewValue && NewValue->m_type) DefaultObj = *NewValue; return DefaultObj; } }; template inline bool operator<(copy_ptr const & a, copy_ptr const & b){return (*a.c_ptr()) < (*b.c_ptr());} template inline bool operator>(copy_ptr const & a, copy_ptr const & b){return (*a.c_ptr()) > (*b.c_ptr());} template inline bool operator<=(copy_ptr const & a, copy_ptr const & b){return (*a.c_ptr()) <= (*b.c_ptr());} template inline bool operator>=(copy_ptr const & a, copy_ptr const & b){return (*a.c_ptr()) >= (*b.c_ptr());} template inline bool operator==(copy_ptr const & a, copy_ptr const & b){return (*a.c_ptr()) == (*b.c_ptr());} template inline bool operator!=(copy_ptr const & a, copy_ptr const & b){return (*a.c_ptr()) != (*b.c_ptr());} #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 // Resolve the ambiguity between our op!= and the one in rel_ops template inline bool operator!=(copy_ptr const & a, copy_ptr const & b){return (*a.c_ptr()) != (*b.c_ptr());} #endif /* Note#1: The ConstructAndDestruct functions have two extra arguments that are not used. These arguments are not required at all in more compliant compilers 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 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 are not needed. Anything pass to these last two arguments will be discarded. */ // The clone function: (Thanks to Kai-Uwe Bux) template < typename T, typename DT> T * copy_ptr_ConstructAndDestruct_default_allocator_(const T * ptr, bool bConstruct, DT* , void*) { if (bConstruct) { DT* d = new DT(*static_cast(ptr)); #ifdef BOOST_ASSERT BOOST_ASSERT(typeid(*static_cast(ptr)) == typeid(*d)); #endif //BOOST_ASSERT return d; } #if !defined(_MSC_VER) || (_MSC_VER > 1200) delete ptr; #else delete const_cast(ptr); //For VC++ 6.0 bug which doesn't allow deletion of constant pointer #endif return NULL; } template < typename T, typename D, class AX_TYPE> T * copy_ptr_ConstructAndDestruct_(const T * ptr, bool bConstruct, D* , AX_TYPE*) { D * Obj = static_cast( ptr ); if (bConstruct) { AX_TYPE alloc; D* tmp_ptr = alloc.allocate(1, NULL); alloc.construct(tmp_ptr, *(Obj)); #ifdef BOOST_ASSERT BOOST_ASSERT(typeid(*tmp_ptr) == typeid(*Obj)); #endif //BOOST_ASSERT return tmp_ptr; } AX_TYPE alloc; alloc.destroy(Obj); alloc.deallocate(Obj, 1); return NULL; } #endif //!copy_ptr_H_HEADER_GUARD_