arbeit
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

smartptr.h

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////
00002 //
00003 //
00004 //  by Joe Kniss
00005 //  jmk@cs.utah.edu
00006 //  June 2003
00007 //
00008 //////////////////////////////////////////////////////////////
00009 
00010 #ifndef __GUTZ_SMARTPTR_DOT_H
00011 #define __GUTZ_SMARTPTR_DOT_H
00012 
00013 // Turns out this is the documentation for the namespace...
00014 
00015 /// GUTZ, the innards of all my applications.
00016 ///  Tons of usefull stuff, that in my mind really should be in 
00017 ///  the C++ standard library, or a Graphics standard libarary.
00018 namespace gutz {
00019 
00020 // forward decl of SmartPtr
00021 template <class T> class SmartPtr;
00022 
00023 //////////////////////////////////////////////////////////////
00024 /// Counted, Derive your class from it if you want SmartPtr s to it.
00025 ///\code
00026 /// class CMyObject : public Counted { ... };
00027 ///\endcode
00028 /// Remember, never create a counted object on the stack!
00029 ///   (unless you never have SmartPtr s to it)
00030 ///
00031 /// TODO: add stack-heap check using operator new and a
00032 ///  a static pointer map.
00033 class Counted {
00034 public:
00035 
00036    virtual ~Counted()                     {}
00037 
00038 protected:
00039    
00040    template< class T > friend class SmartPtr;
00041    template< class T > friend class SmartPtrRef;
00042 
00043    /// gutz::Counted interface, increment reference count by one.
00044    ///   Not generaly used by subclasses, mostly for 
00045    ///   collaboration with gutz::SmartPtr.  Sometimes
00046    ///   you need to call this though, see the 
00047    ///   documentation for gutz::SmartPtr
00048    virtual void _incCount()               {++_count; }
00049    /// gutz::Counted interface, decrement reference count by one.
00050    ///   Not generaly used by subclasses, mostly for 
00051    ///   collaboration with gutz::SmartPtr.  Sometimes
00052    ///   you need to call this though, see the 
00053    ///   documentation for gutz::SmartPtr
00054    virtual void _decCount()               {--_count; }
00055    /// gutz::Counted interface, get the current reference count.
00056    ///   Not generaly used by subclasses, mostly for 
00057    ///   collaboration with gutz::SmartPtr.  
00058    virtual int  _getCount() const         {return _count;}
00059 
00060    /// protected constructor since this class does nothing by itself
00061    Counted(const Counted &c):_count(0)    {}
00062    /// need to handle this correctly
00063    Counted &operator=(const Counted &c)   {return *this;}
00064    /// default constructor, protected!
00065    Counted():_count(0) {}
00066 private:
00067    /// Counted: reference count, if _getCount() == 0 then delete
00068    int _count;  
00069 };
00070 
00071 
00072 
00073 //////////////////////////////////////////////////////////////
00074 /// Smart Pointer class.
00075 ///   Smart Pointers are FUN FUN FUN.
00076 ///
00077 /// For all intents an purposes, SmartPtrs work just like regular
00078 ///  pointers, for instance you can:
00079 /// \code
00080 ///   gutz::SmartPtr<MyClass> mcsp(); // create a "0" (Null) pointer by default
00081 ///   mcsp = new MyClass();           // assign a pointer
00082 ///   if( mcsp )                      // check if the pointer is non-zero
00083 ///   if( !mcsp )                     // check if the pointer is zero
00084 ///   if( mcsp == mcp )               // compare against another SmartPtr or raw pointer
00085 ///   mcsp->myFunction();             // call a member function
00086 ///   (*mcsp) = blah;                 // de-refrence
00087 ///
00088 ///   // declaration of some function taking a pointer to MyClass
00089 ///   void someFunc(MyClass *mcp);
00090 ///   // call that function, but let the SmartPtr auto-cast to a pointer
00091 ///   someFunc( mcsp ); // works fine too
00092 /// \endcode
00093 ///  The difference is that you don't need to call delete on your
00094 ///   pointer, the SmartPtr<> will delete it when it gets deleted
00095 ///   AND holds the last reference to that object.  Just imagine a world
00096 ///   with no memory leaks. 
00097 ///
00098 ///  Const SmartPtrs work just like const ptrs. 
00099 /// \code const SmartPtr<T> ~= T const* \endcode
00100 ///  You can always get at the "raw" pointer using:
00101 /// \code mySP.getPtr(); \endcode;
00102 ///
00103 ///  There is one major caveaut: Any class that can have a SmartPtr
00104 ///   to it MUST be a subclass of gutz::Counted.  This insures that
00105 ///   we only have one (1) reference counter to any pointer, since it
00106 ///   is a member of the class rather than a "proxy-class".  One day I will 
00107 ///   implement an "AutoDeletPtr"  which allows you to do the same thing with 
00108 ///   non-Counted classes.  Forcing a Counted subclass, however, has advantages:
00109 ///  - You can cast to different levels of the hierarchy and still have valid SmartPtrs
00110 ///  - You can convert a pointer to a SmartPtr any time and still have valid refcounts
00111 ///  - A Counted Base class insures, via type checking, that we have only 1 refcounter per ptr
00112 ///
00113 ///  SmartPtr is itself a subclass of counted so that you can have
00114 ///  SmartPtrs to SmartPtrs and SmartPtrRef s.
00115 ///
00116 ///   Notes:  Having issues?
00117 ///   You shouldn't create a Counted object on the stack.
00118 ///    If you do, and somebody else gets a smart pointer to
00119 ///    that object, the smartptr will call delete on 
00120 ///    stack memory when the refcount drops to 0, which it
00121 ///    might if the function doesn't delete the object
00122 ///    first, both cases are bad.  
00123 ///    Here is an example that would cause an error.   
00124 ///\code
00125 ///  SmartPtr<T> newObjSP;
00126 ///  T newObj;
00127 ///  newObjSP = &newObj;
00128 ///\endcode
00129 ///   Notice that newObj is a local (stack) object.
00130 ///   The right way:
00131 ///\code
00132 ///  SmartPtr<T> newObjSP = new T;
00133 ///\endcode
00134 ///   the new object will get deleted when no one else has
00135 ///   a reference to it.
00136 ///
00137 ///  Another caveaut of smartptrs is that if an object is
00138 ///  using a smartptr to itself (why? who knows?), when 
00139 ///  the smartptr is deleted it might just delete the object
00140 ///  that is using it.  This happens especially when the 
00141 ///  constructor uses the smartptr, badness!  If 
00142 ///  you have to do this, you need to increment your own
00143 ///  reference counter first, then decrement when the ptr
00144 ///  is gone (to avoid memory leaks).  Again, be carefull,
00145 ///  if the smartptr is created on the stack, you're pretty 
00146 ///  much screwed, because you can't possibly decrement
00147 ///  after the smartptr is deleted.  This reference to self
00148 ///  situation can come up when iterators use smartptrs to the
00149 ///  object they are iterating through.  If the iterator is
00150 ///  used internally, then when it goes away, the object itself
00151 ///  might get deleted. Like say, when you need to iterate 
00152 ///  through yourself in the constructor :)  You know you are
00153 ///  getting into the danger zone when you do this 
00154 ///   (no pun intended):
00155 ///\code
00156 ///  // somewhere in a member function of "MyObj"
00157 ///  SmartPtr<MyObj> s(this);  /// this!!!
00158 ///\endcode
00159 ///   The right way would be:
00160 ///\code
00161 ///  // somewhere in a member function of "MyObj"
00162 ///  _incCount();
00163 ///  SmartPtr<MyObj> *sp = new SmartPtr<MyObj>(this);
00164 ///   <... do what you gota do ...>
00165 ///  delete sp;
00166 ///  _decCount();
00167 ///\endcode
00168 ///   Function calls are often the culprit, but this case is 
00169 ///   simpler, just inc and dec around the call:
00170 ///\code
00171 ///  // somewhere in a member function of "MyObj"
00172 ///  _incCount();
00173 ///  someFunctionUsingSPs(SmartPtr<MyObj>(this));
00174 ///  _decCount();
00175 ///\endcode
00176 ///  Remember, this only applies to use of a smartptr to "this" in
00177 ///  the objects member functions, or any function call using the "this" 
00178 ///  pointer or a SmartPtr to "this" in the objects constructors.
00179 template <class T> 
00180 class SmartPtr : public Counted 
00181 {
00182 public:
00183    typedef T type;
00184 
00185    SmartPtr()                                  { _ref = 0; }
00186    SmartPtr(T* const ptr)                      { _ref = 0; assign(ptr);}
00187    SmartPtr(const SmartPtr &sp)                { _ref = 0; assign(sp._ref);}
00188    virtual ~SmartPtr()                         { assign((T*)0); }
00189 
00190    //////////////////////////////////////////
00191    ///@name get the contained pointer
00192    ///@{
00193    T*       getPtr()                           { return _ref; }
00194    T* const getPtr() const                     { return _ref; }
00195    ///@}
00196 
00197    //////////////////////////////////////////
00198    ///@name assign another smart pointer, or a raw pointer
00199    ///@{
00200    SmartPtr & operator = (const SmartPtr &sp)  {assign(sp._ref); return *this;}
00201    // assign pointer or NULL
00202    T *operator = (T* const ptr)                {assign(ptr); return getPtr();}
00203    ///@}
00204 
00205    //////////////////////////////////////////
00206    ///@name access members of T
00207    ///    ex \code mySmartPtr->myFunction() \endcode
00208    ///@{
00209    T*       operator ->()                      { return getPtr(); }
00210    T* const operator ->() const                { return getPtr(); }
00211    ///@}
00212 
00213    /////////////////////////////////////////
00214    ///@name De-reference like a regular pointer
00215    ///     ex \code (*mySmartPtr).myFunction() \endcode
00216    ///@{
00217    T&       operator*()                        { return *getPtr(); }
00218    T&       operator*() const                  { return *getPtr(); }
00219    ///@}
00220 
00221    //////////////////////////////////////////
00222    ///@name Implicit conversion to T* 
00223    ///   good for function calls that take a 
00224    ///     regular pointer, for example: 
00225    /// \code 
00226    ///   ///declaration of some function, taking a pointer
00227    ///   void someFunc(someType *sc);
00228    ///   ///calling "someFunc" using a smartptr as the parameter
00229    ///   someFunc( mySP2someType );  /// converts SP to a raw pointer implicitly
00230    /// \endcode 
00231    ///   also needed for "if" tests:
00232    /// \code  if( mySP2someType ) /// test if ptr != 0 \endcode
00233    ///@{
00234    operator T* const () const                        { return getPtr();}
00235    //operator T*       ()                              { return getPtr();}
00236    ///@}
00237 
00238    //////////////////////////////////////////
00239    ///@name Casting for convenience
00240    ///  Handles dynamic cast for you.
00241    ///@{
00242    
00243    /// \code
00244    ///   mySubClassSP  = myBaseClassSP.down_cast<MySubClassType>();
00245    /// \endcode
00246    ///  You don't need this for an "up-cast" since this thing automatically
00247    ///  casts itself to a pointer which will then be up-casted by the compiler.
00248    template< class CT >
00249       SmartPtr<CT> cast() const 
00250    { return SmartPtr<CT>((CT*const)dynamic_cast<CT*const>(_ref)); }
00251    ///@}
00252 
00253    //////////////////////////////////////////
00254    ///@name utilities, comparison ops
00255    /// just like raw ptrs, 
00256    /// \code
00257    /// if(SP != 0)... 
00258    /// if(SP == NULL)
00259    /// \endcode
00260    ///@{
00261    bool operator!()                       const { return getPtr()==0;}
00262 #if 0 // these are completely redundant because of the auto cast
00263    bool operator==(const T *const ptr)    const { return getPtr()==ptr; }
00264    bool operator==(const SmartPtr<T> &sp) const { return getPtr()==sp.getPtr();}
00265    bool operator!=(const T *const ptr)    const { return getPtr()==ptr; }
00266    bool operator!=(const SmartPtr<T> &sp) const { return getPtr()!=sp.getPtr();}
00267    /// these may or maynot be what you want! be carefull
00268    /// they compare pointer values..
00269    bool operator<(const SmartPtr<T> &sp)  const { return getPtr()<sp.getPtr();}
00270    bool operator<=(const SmartPtr<T> &sp) const { return getPtr()<=sp.getPtr();}
00271    bool operator>(const SmartPtr<T> &sp)  const { return getPtr()>sp.getPtr();}
00272    bool operator>=(const SmartPtr<T> &sp) const { return getPtr()>=sp.getPtr();}
00273 #endif
00274    /// just for convienence. access via,
00275    /// \code mySp.isNull() \endcode 
00276    bool isNull() const                           { return (getPtr()==0); }
00277    ///@}
00278 
00279 
00280 protected:
00281    /// The only data we have is this pointer, so we have the same memory
00282    ///   foot print of a regular pointer.
00283    T *_ref;
00284 
00285    void assign(T* const ref)
00286    {
00287       /// inc ref if non-zero
00288       if(ref!=0) ref->_incCount();
00289       /// save off old reference
00290       T *oldref = _ref;           
00291       /// assign _ref = ref
00292       _ref = ref;                 
00293       /// delete the old reference
00294       if(oldref!=0){
00295          /// just a dec most of the time...
00296          oldref->_decCount();
00297          /// but if we hold the last reference, nuke it
00298          if((oldref->_getCount() <= 0))
00299          {
00300             delete oldref;
00301          }
00302       }
00303    }
00304 
00305 };
00306 
00307 //////////////////////////////////////////////////////////////
00308 /// Smart Pointer Reference class, behaves like a 
00309 ///   reference to a pointer.
00310 /// This class can be used for clean double indirection
00311 /// of objects, ie. when an object changes all those with
00312 /// one of these objects referencing it will see the 
00313 /// changes.  Great for volitle pointers.
00314 //////////////////////////////////////////////////////////////
00315 template<class T>
00316 class SmartPtrRef {
00317 public:
00318    typedef SmartPtr<T> type;
00319 
00320    SmartPtrRef()                            { _ref = 0; assign(new type(0));}
00321    SmartPtrRef(T * ptr)                     { _ref = 0; assign(new type(ptr));}
00322    SmartPtrRef(const SmartPtrRef &dsp)      { _ref = 0; assign(dsp._ref); }
00323    SmartPtrRef(SmartPtr<T> *sp)             { _ref = 0; assign(sp);}
00324    virtual ~SmartPtrRef()                   { assign((type*)0); }
00325 
00326    //////////////////////////////////////////
00327    ///@name get the contained pointer
00328    ///@{
00329    T*       getPtr()                           { return _ref->getPtr(); }
00330    T const* getPtr() const                     { return _ref->getPtr(); }
00331    ///@}
00332 
00333    //////////////////////////////////////////
00334    ///@name assign smart pointer, remember this is 
00335    /// a reference to a pointer, not a pointer.
00336    ///@{ 
00337    SmartPtrRef & operator= (const SmartPtrRef &sp) { *_ref = *(sp._ref); return *this;}
00338    // assign pointer or NULL
00339    T *operator = (T * ptr)                     {*_ref = ptr; return ptr;}
00340    ///@}
00341 
00342    //////////////////////////////////////////
00343    ///@name access members of T
00344    ///   ex. T->myFunction()
00345    ///@{
00346    T*       operator ->()                      { return getPtr(); }
00347    T const* operator ->() const                { return getPtr(); }
00348    ///@}
00349 
00350    /////////////////////////////////////////
00351    ///@name De-reference like a regular pointer
00352    ///   ex (*mySmartPRef).myFunction()
00353    ///@{
00354    T&       operator*()                        { return *getPtr(); }
00355    T const& operator*() const                  { return *getPtr(); }
00356    ///@}
00357 
00358    //////////////////////////////////////////
00359    /// Implicit conversion to T* (for function calls)
00360    operator T* () { return _ref.getPtr();}
00361 
00362 
00363    //////////////////////////////////////////
00364    ///@name utilities, comparison ops
00365    ///    just like raw ptrs, if(T != 0)... if(T == NULL)
00366    ///@{
00367    bool operator!()                       const { return getPtr()==0;}
00368    bool operator==(const T* ptr)          const { return getPtr()==ptr; }
00369    bool operator==(const SmartPtrRef &sp) const { return getPtr()==sp.getPtr();}
00370    bool operator!=(const T* ptr)          const { return getPtr()==ptr; }
00371    bool operator!=(const SmartPtrRef &sp) const { return getPtr()!=sp.getPtr();}
00372    /// these may or maynot be what you want! be carefull
00373    bool operator<(const SmartPtrRef &sp)  const { return getPtr()<sp.getPtr();}
00374    bool operator<=(const SmartPtrRef &sp) const { return getPtr()<=sp.getPtr();}
00375    bool operator>(const SmartPtrRef &sp)  const { return getPtr()>sp.getPtr();}
00376    bool operator>=(const SmartPtrRef &sp) const { return getPtr()>=sp.getPtr();}
00377    /// for convienence since if(mySP) is always true,
00378    /// use if(!myPtr.isNull())...
00379    ///@}
00380    bool isNull() const                          { return (getPtr()==0); }
00381 
00382    //////////////////////////////////////////
00383    /// Private from here down
00384 protected:
00385    type *_ref;
00386 
00387    void assign(type *ref)
00388    {
00389       /// add a reference to the new guy
00390       if(ref!=0) ref->_incCount(); 
00391       type *oldref = _ref;           //< save off old reference
00392       _ref = ref;                    //< assign new guy
00393       /// deleting the old guy
00394       if(oldref!=0){
00395          /// just a dec most of the time
00396          oldref->_decCount();
00397          /// but if we are the last reference, nuke it
00398          if(oldref->_getCount() <= 0)
00399          {
00400             delete oldref;
00401          }
00402       }
00403    }
00404 };
00405 
00406 
00407 } /// end namespace gutz
00408 
00409 #endif

Send questions, comments, and bug reports to:
jmk