smartptr.h

Go to the documentation of this file.
00001 
00010 /*
00011  *  Important Note: 
00012  *  This code originally comes from www.codeproject.com
00013  *  and was written by Sandu Turcan (idlsoft@hotmail.com)
00014  *  The code has been modified, with permission, and in this
00015  *  version is covered by the terms of the following licence:
00016  *
00017  *  Copyright (c) 2003, Matt Beard
00018  *
00019  *  This software is provided 'as-is', without any express or implied warranty.
00020  *  In no event will the authors be held liable for any damages arising from
00021  *  the use of this software.
00022  *
00023  *  Permission is granted to anyone to use this software for any purpose,
00024  *  including commercial applications, and to alter it and redistribute it
00025  *  freely, subject to the following restrictions:
00026  *
00027  *    1. The origin of this software must not be misrepresented; you must
00028  *       not claim that you wrote the original software. If you use this
00029  *       software in a product, an acknowledgment in the product
00030  *       documentation would be appreciated but is not required.
00031  *  
00032  *    2. Altered source versions must be plainly marked as such, and must
00033  *       not be misrepresented as being the original software.
00034  *  
00035  *    3. This notice may not be removed or altered from any source
00036  *       distribution.
00037  */
00038 
00039 #ifndef MXFLIB__SMARTPTR_H
00040 #define MXFLIB__SMARTPTR_H
00041 
00042 // Pointer debug enable and disable
00043 //#define PTRDEBUG( x ) x
00044 #define PTRDEBUG( x )
00045 
00046 // Pointer checking enable and disable (takes a lot of CPU time)
00047 // If this is enabled the application code must instantiate and check PtrCheckList
00048 //#define PTRCHECK( x ) x
00049 #define PTRCHECK( x )
00050 
00051 
00052 // Ensure we know NULL
00053 #include <stdlib.h>
00054 
00055 namespace mxflib 
00056 {
00057     // Forward declaration of SmartPtr to allow it to be befreinded
00058     template <class T> class SmartPtr;
00059 
00060     // Forward declare ParentPtr to allow it to be used in RefCount<>
00061     template <class T> class ParentPtr;
00062 
00064 
00067     template <class T> class IRefCount 
00068     {
00069         // Allow SmartPtr access to our internals
00070         friend class SmartPtr<T>;
00071         
00072         // Allow ParentPtr access to our internals
00073         friend class ParentPtr<T>;
00074 
00075     protected:
00076         // A number of pure virtual functions that the reference counter needs
00077         
00078         virtual void __IncRefCount() = 0;               
00079         virtual void __DecRefCount() = 0;               
00080         virtual T * GetPtr() = 0;                       
00081         virtual IRefCount<T> * GetRef() = 0;            
00082 
00083         virtual void AddRef(ParentPtr<T> &Ptr) = 0;     
00084         virtual void DeleteRef(ParentPtr<T> &Ptr) = 0;  
00085         virtual void ClearParents(void) = 0;            
00086         
00087         virtual ~IRefCount() {};
00088     };
00089 
00090     // Definitions for running memory leak tests
00091     typedef std::pair<void*,std::string> PtrCheckListItemType;
00092     typedef std::list<PtrCheckListItemType> PtrCheckListType;
00093     PTRCHECK( extern PtrCheckListType PtrCheckList; )
00094 }
00095 
00096 
00097 namespace mxflib 
00098 {
00099 
00101 
00113     template <class T> class RefCount : public IRefCount<T>
00114     {
00115     protected:
00116         int __m_counter;                                    
00117 
00118         typedef ParentPtr<T> LocalParent;                   
00119         typedef std::list<LocalParent*> LocalParentList;    
00120         LocalParentList *ParentPointers;                    
00121 
00122     protected:
00124         virtual void __IncRefCount()
00125         {
00126             __m_counter++;
00127 
00128             PTRDEBUG( debug("%p Increment count -> %p\n", this, __m_counter); )
00129         }
00130 
00132         virtual void __DecRefCount()
00133         {
00134             __m_counter--;
00135 
00136             PTRDEBUG( debug("%p Decrement count -> %d\n", this, __m_counter); )
00137 
00138             if(__m_counter<=0)
00139             {
00140                 PTRDEBUG( debug("%p Destroying\n", this); )
00141 
00142                 __DestroyRef();
00143             }
00144         }
00145 
00147         virtual T * GetPtr()
00148         {
00149             return ((T *)this);
00150         }
00151 
00153         virtual IRefCount<T>* GetRef()
00154         {
00155             return this;
00156         }
00157 
00159 
00161         virtual void __DestroyRef() 
00162         { 
00163             if(GetPtr()!=NULL)
00164             {
00165                 // If we are "checking" locate and remove our entry
00166                 PTRCHECK
00167                 ( 
00168                     PtrCheckListType::iterator it = PtrCheckList.begin();
00169                     while(it != PtrCheckList.end())
00170                     {
00171                         if((*it).first == (void*)this)
00172                         {
00173                             PtrCheckList.erase(it);
00174                             break;
00175                         }
00176                         it++;
00177                     }
00178                 )
00179 
00180                 delete GetPtr();
00181             }
00182         }
00183 
00185         virtual void AddRef(ParentPtr<T> &Ptr)
00186         {
00187             PTRDEBUG( debug("Adding ParentPtr(%p) to %p\n", &Ptr, this); )
00188             
00189             if(!ParentPointers) ParentPointers = new LocalParentList;
00190             ParentPointers->push_back(&Ptr);
00191         }
00192 
00194         virtual void DeleteRef(ParentPtr<T> &Ptr)
00195         {
00196             if(ParentPointers)
00197             {
00198                 typename LocalParentList::iterator it = ParentPointers->begin();
00199                 while(it != ParentPointers->end())
00200                 {
00201                     if((*it) == &Ptr)
00202                     {
00203                         PTRDEBUG( debug("Deleting ParentPtr(%p) from %p\n", &Ptr, this); )
00204                         ParentPointers->erase(it);
00205                         return;
00206                     }
00207                     it++;
00208                 }
00209             }
00210             error("Tried to clear ParentPtr(%p) from %p but that ParentPtr does not exist\n", &Ptr, this);
00211         }
00212 
00213     protected:
00215         RefCount()
00216         {
00217             // If we are "checking" add entry to the list
00218             // We add to the start of the list as this gives the best chance of finding the
00219             // item quickly when it is deleted (most objects are first-in-last-out)
00220             PTRCHECK( PtrCheckList.push_front(PtrCheckListItemType((void*)this, PrintInfo())); )
00221 
00222             // No references yet!
00223             __m_counter = 0;
00224 
00225             // No parent pointers (yet) reference this item
00226             ParentPointers = NULL;
00227 
00228             PTRDEBUG( debug("%p Build new (zero) count\n", this); )
00229         }
00230 
00231 
00233         virtual ~RefCount() 
00234         {
00235             if(ParentPointers) ClearParents(); 
00236         }
00237 
00239         virtual void ClearParents(void);
00240 
00241         PTRCHECK
00242         (
00243         public:
00244             virtual std::string PrintInfo(void)
00245             {
00246                 char buffer[1024];
00247                 sprintf(&buffer[0], "Item size = %d :", sizeof(T));
00248                 for(int i=0; i<min(sizeof(T), 64); i++) sprintf(&buffer[strlen(buffer)], " %02x", ((UInt8*)(this))[i]);
00249                 return std::string(buffer);
00250             }
00251 
00252             void SetDebug(std::string str)
00253             {
00254                 PtrCheckListType::iterator it = PtrCheckList.begin();
00255                 while(it != PtrCheckList.end())
00256                 {
00257                     if((*it).first == (void*)this)
00258                     {
00259                         PTRDEBUG( debug("Setting text to (%s)\n", str.c_str()); )
00260                         (*it).second = str;
00261                         return;
00262                     }
00263                     it++;
00264                 }
00265             }
00266         )
00267     };
00268 
00269     // Clear all parent pointers
00270     template <class T> void mxflib::RefCount<T>::ClearParents(void)
00271     {
00272         if(ParentPointers)
00273         {
00274             typename LocalParentList::iterator it = ParentPointers->begin();
00275             while(it != ParentPointers->end())
00276             {
00277                 (*it)->ClearFromParent();
00278                 it++;
00279             }
00280 
00281             delete ParentPointers;
00282         }
00283     }
00284 }
00285 
00286 
00287 namespace mxflib
00288 {
00290 
00333     template <class T> class SmartPtr 
00334     {
00335     protected:
00336         IRefCount<T> *__m_refcount;     
00337 
00339         PTRDEBUG( std::string DebugName; )
00340         
00342 
00345         class __RefCounter : public RefCount<T>
00346         {
00347         private:
00348             T *__m_ptr;                 
00349         protected:
00351             virtual T * GetPtr() const { return __m_ptr; }
00352 
00354 
00356             virtual void __DestroyRef() { delete this; }
00357 
00358         public:
00360             __RefCounter(T *ptr)
00361             {
00362                 __m_ptr = ptr;
00363             }
00364 
00366             virtual ~__RefCounter()
00367             {
00368                 RefCount<T>::__DestroyRef();
00369             }
00370         };
00371 
00373 
00376 /*  DRAGONS: Removed to allow kludge to fix gcc 3.3.x bug
00377         void __Assign(void *ptr)
00378         {
00379             if(ptr==NULL)
00380                 __Assign((IRefCount<T> *)NULL);
00381             else
00382             {
00383                 __Assign(new __RefCounter(static_cast<T *>(ptr)));
00384             }
00385         }
00386 */
00387 
00388 /*  DRAGONS:  KLUDGE to fix gcc 3.3.x bug - remove generic assign and force all smart pointer targets to be derived from IRefCount<> */
00389 /*  DRAGONS:  If this klidge is undone ParentPtr will need updating to ensure it works with non-RefCount versions */
00390 
00392 
00399         virtual void __Assign(IRefCount<T> *refcount)
00400         {
00401             PTRDEBUG( if(DebugName.size()) debug("%s changing from %p to %p\n", DebugName.c_str(), __m_refcount, refcount); )
00402 
00403             // Attach us to the new object first
00404             // This is important in case we are assigned to
00405             // the same thing we are already attatched to,
00406             // in which case detatching first could cause
00407             // our object to be deleted!!
00408             if(refcount!=NULL) refcount->__IncRefCount();
00409 
00410             // Record what we were attached to
00411             IRefCount<T> *oldref = __m_refcount;
00412 
00413             // Make the new attachment
00414             __m_refcount = refcount;
00415 
00416             // Break the old attachment
00417             if(oldref!=NULL) oldref->__DecRefCount();
00418         }
00419 
00420     public:
00422         SmartPtr()
00423         {
00424             __m_refcount = NULL;
00425         }
00426 
00428         SmartPtr(IRefCount<T> * ptr)
00429         {
00430             __m_refcount = NULL;
00431             __Assign(ptr);
00432         }
00433 
00435         SmartPtr(const SmartPtr<T> &sp)
00436         {
00437             __m_refcount = NULL;
00438             __Assign(sp.__m_refcount);
00439         }
00440 
00442         virtual ~SmartPtr()
00443         {
00444             __Assign((IRefCount<T> *)NULL);
00445         }
00446 
00448         T *GetPtr() const
00449         {
00450             if(__m_refcount==NULL) return NULL;
00451             return __m_refcount->GetPtr();
00452         }
00453 
00455         IRefCount<T> *GetRef() const
00456         {
00457             if(__m_refcount==NULL) return NULL;
00458             return __m_refcount->GetRef();
00459         }
00460 
00462         SmartPtr & operator = (const SmartPtr<T> &sp) {__Assign(sp.__m_refcount); return *this;}
00463 
00465         SmartPtr & operator = (IRefCount<T> * ptr) {__Assign(ptr); return *this;}
00466 
00468         T * operator ->()
00469         {
00470             ASSERT(GetPtr()!=NULL);
00471             return GetPtr();
00472         }
00473 
00475         const T * operator ->() const
00476         {
00477             ASSERT(GetPtr()!=NULL);
00478             return (const T*)GetPtr();
00479         }
00480 
00482         operator T* () const
00483         {
00484             return GetPtr();
00485         }
00486 
00488         bool operator !()
00489         {
00490             return GetPtr()==NULL;
00491         }
00492 
00494         bool operator ==(const SmartPtr &sp)
00495         {
00496             return GetPtr()==sp.GetPtr();
00497         }
00498 
00500         bool operator !=(const SmartPtr &sp)
00501         {
00502             return GetPtr()!=sp.GetPtr();
00503         }
00504 
00506         bool operator<(SmartPtr &Other) { return this.operator<(*Other->GetPtr()); }
00507 
00509 
00514         template <class U> U* Cast(U*) { return dynamic_cast<U*>(GetPtr()); } 
00515 
00517         PTRDEBUG( void SetDebugName(std::string Name) { DebugName = Name; } )
00518     };
00519 }
00520 
00521 
00522 namespace mxflib
00523 {
00525 
00529     // DRAGONS: Strict C++ compilers (such as GCC 3.4.x) require members of superclass templates to be referenced by this-> to remove possilbe ambiguities
00530     template<class T> class ParentPtr : public SmartPtr<T>
00531     {
00532     protected:
00534 
00537         virtual void __Assign(IRefCount<T> *refcount)
00538         {
00539             PTRDEBUG( debug("Assigning parent pointer at %p to %p\n", this, refcount); )
00540 
00541             // Remove us from the old parent's list of parent pointers
00542             if(this->__m_refcount) this->__m_refcount->DeleteRef(*this);
00543 
00544             // Make the new attachment
00545             this->__m_refcount = refcount;
00546 
00547             // Add us to the new parent's list of parent pointers (so we will be cleared if it is deleted)
00548             if(refcount) refcount->AddRef(*this);
00549         }
00550 
00551     public:
00553         ParentPtr()
00554         {
00555             this->__m_refcount = NULL;
00556         }
00557 
00559         ParentPtr(SmartPtr<T> ptr)
00560         {
00561             this->__m_refcount = NULL;
00562             __Assign(ptr.GetRef());
00563         }
00564 
00566         ParentPtr(IRefCount<T> * ptr)
00567         {
00568             this->__m_refcount = NULL;
00569             __Assign(ptr);
00570         }
00571 
00573         ParentPtr(const ParentPtr &rhs)
00574         {
00575             this->__m_refcount = NULL;
00576             __Assign(rhs.GetRef());
00577         }
00578 
00580         ~ParentPtr()
00581         {
00582             // Remove us from the old parent's list of parent pointers
00583             if(this->__m_refcount) (this->__m_refcount)->DeleteRef(*this);
00584 
00585             this->__m_refcount = NULL;
00586         }
00587 
00589         ParentPtr & operator=(const SmartPtr<T> &sp) { __Assign(sp.GetRef()); return *this;}
00590 
00592         ParentPtr & operator=(const ParentPtr<T> &sp) { __Assign(sp.__m_refcount); return *this;}
00593 
00595         ParentPtr & operator=(T *Ptr) { __Assign((IRefCount<T>*)Ptr); return *this; }
00596 
00598         void Clear(void) 
00599         {
00600             // Remove us from the old parent's list of parent pointers
00601             if(this->__m_refcount) this->__m_refcount->DeleteRef(*this);
00602 
00603             this->__m_refcount = NULL; 
00604         }
00605 
00607 
00608         void ClearFromParent(void) { this->__m_refcount = NULL; };
00609     };
00610 }
00611 
00612          
00614 #define SmartPtr_Cast(Ptr, Type) ( Ptr.Cast((Type*)NULL) )
00615 
00616 #endif // MXFLIB__SMARTPTR_H

Generated on Mon Apr 2 15:20:54 2007 for MXFLib by  doxygen 1.5.1-p1