smart_ptr.h

Go to the documentation of this file.
00001 /*
00002  * smart_ptr.h
00003  *
00004  * Copyright 2002,2009 Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Yet ANOTHER smart ptr.  This is basically the std::auto_ptr<T>,
00032  * but it has special copy/assignment operators so it can be used
00033  * in STL collections.
00034  */
00035 
00036 #ifndef WAVEPACKET_SMART_PTR_H__
00037 #define WAVEPACKET_SMART_PTR_H__
00038 
00039 
00040 // includes --------------------------------------------------------------------
00041 #include "threadsafe_counter.h"
00042 
00043 
00044 /// \ingroup threadsafe
00045 /*@{*/
00046 
00047 /// Auto-destructing pointer class.
00048 ///
00049 /// This is a ref-counting class.  It keeps the ref struct as a separate
00050 /// struct on the heap, and all smart pointers share it.
00051 ///
00052 /// \b WARNING: you will really hose yourself if you have two or more smart_ptr's
00053 /// wrapping the same underlying pointer if they use different ref structs.
00054 /// The way to avoid this is to use smart_ptr<T>'s everywhere (never convert to
00055 /// a raw T* and then pass to another smart_ptr<T>, for instance). 
00056 ///
00057 /// This class is PARTLY threadsafe!  That is, there is a mutex protecting the ref
00058 /// count.  This is a slight overhead for single-threaded applications, but is
00059 /// probably worth it overall.  General smart_ptr<T> accesses such as
00060 /// \verbatim  p->doSomething()  \endverbatim
00061 /// don't pay any synchronization
00062 /// overhead.  Only operations that impact the ref count (assignment,
00063 /// destruction, etc.) will synchronize.
00064 ///
00065 /// Put another way, accessing the pointer is NOT synchronized (and therefore
00066 /// not generally threadsafe).  If your class
00067 /// needs that, you'll need to make the class itself threadsafe.
00068 template <class T>
00069 class smart_ptr
00070 {
00071 public:
00072         // constructors --------------------------------------------------------
00073         smart_ptr(T * pT = NULL) throw() : m_prefcount(NULL), m_pT(NULL) {
00074                 this->assign(pT);
00075         }
00076 
00077         template <class X>
00078         smart_ptr(IN const smart_ptr<X>& from) throw() :
00079             m_prefcount(NULL), m_pT(NULL) {
00080                 this->assign(from);
00081         }
00082 
00083         smart_ptr(IN const smart_ptr<T>& from) throw() :
00084             m_prefcount(NULL), m_pT(NULL) {
00085                 this->assign(from);
00086         }
00087         
00088         // destructor ----------------------------------------------------------
00089         ~smart_ptr(void) throw() { this->release(); }
00090 
00091         // operators -----------------------------------------------------------
00092         T * operator -> (void) throw() {
00093                 ASSERT(m_pT, "NULL smart pointer");
00094                 return m_pT;
00095         }
00096 
00097         const T * operator -> (void) const throw() {
00098                 ASSERT(m_pT, "NULL smart pointer");
00099                 return m_pT;
00100         }
00101 
00102         operator T * (void) throw() {
00103                 return m_pT;
00104         }
00105 
00106         operator const T * (void) const throw() {
00107                 return m_pT;
00108         }
00109 
00110         bool operator ! (void) const throw() {
00111                 return !m_pT;
00112         }
00113 
00114         const smart_ptr<T>& operator = (IN T * pT) throw() {
00115                 this->assign(pT);
00116                 return *this;
00117         }
00118 
00119         template <class X>
00120         const smart_ptr<T>& operator = (IN const smart_ptr<X>& from) throw() {
00121                 this->assign(from);
00122                 return *this;
00123         }
00124 
00125         const smart_ptr<T>& operator = (IN const smart_ptr<T>& from) throw() {
00126                 this->assign(from);
00127                 return *this;
00128         }
00129 
00130         long get_ref_count(void) const throw() {
00131                 return (m_prefcount) ? m_prefcount->getCount() : 0;
00132         }
00133 
00134         T * disown(void) throw() {
00135                 // releases refs without destroying object.
00136                 // only works if only 1 ref remains!
00137                 ASSERT(m_prefcount && m_pT,
00138                     "calling disown() on empty smart_ptr<T>");
00139                 ASSERT(!m_prefcount->decrement(),
00140                     "Can only disown() smart_ptr<T>'s with 1 ref");
00141                 delete m_prefcount;
00142                 m_prefcount = NULL;
00143                 T * pT = m_pT;
00144                 m_pT = NULL;
00145                 return pT;
00146         }
00147 
00148 private:
00149         // private typedefs ----------------------------------------------------
00150 
00151         // private helper methods ----------------------------------------------
00152         void assign(IN T * pT) throw() {
00153                 this->release();
00154                 if (pT) {
00155                         m_prefcount = new threadsafe_counter;
00156                         ASSERT(m_prefcount, "out of memory");
00157                         m_prefcount->increment();
00158                         m_pT = pT;
00159                 }
00160         }
00161 
00162         template <class X>
00163         void assign(IN const smart_ptr<X>& from) throw() {
00164                 this->release();
00165 
00166                 // nasty cast to get rid of const-ness, and type!
00167                 smart_ptr<T> * pfoo =
00168                     (smart_ptr<T> *) ((void *) &from);
00169 
00170                 // force from to increment so it doesn't get nuked on another
00171                 //    thread.
00172                 // so long as ref counts aren't corrupted, this should avoid
00173                 //    all such race conditions.
00174                 long incCount = pfoo->increment();
00175                 if (incCount < 2) {
00176                         // from is dead or dying!  no object to copy
00177                         pfoo->decrement();
00178                         return;
00179                 }
00180 
00181                 // FROM HERE ON OUT WE HAVE TO MAKE SURE WE CALL pfoo->decrement
00182                 //   or else we hang on to the incremented count for ourselves
00183 
00184                 // make sure we can safely cast from X to T
00185                 const X * pX = (const X *) from;
00186                 const T * pT = dynamic_cast<const T *>(pX);
00187                 if (!pT) {
00188                         // can't cast, so this isn't a valid assignment
00189                         pfoo->decrement();
00190                         return;
00191                 }
00192 
00193                 // non-null?
00194                 ASSERT(pT, "should have non-null pointer");
00195 
00196                 // another nasty cast
00197                 T * new_pT = (T *) pT;
00198 
00199                 // store ref pointer, and copy object pointer
00200                 m_prefcount = pfoo->m_prefcount;
00201                 m_pT = new_pT;
00202 
00203                 // we already took a new ref (pfoo->increment(), above) so we
00204                 //   are all done
00205         }
00206 
00207         void release(void) throw() {
00208                 if (m_prefcount) {
00209                         // decrement count
00210                         long count = m_prefcount->decrement();
00211                         if (count < 1) {
00212                                 // we had the last ref!  destroy everything
00213                                 m_prefcount->increment();   // avoid re-entry
00214                                 delete m_pT;
00215                                 delete m_prefcount;
00216                         }
00217 
00218                         // clear all state
00219                         m_prefcount = NULL;
00220                         m_pT = NULL;
00221                 }
00222                 ASSERT(!m_pT && !m_prefcount, "Invalid release");
00223         }
00224 
00225         long increment(void) throw() {
00226                         if (m_prefcount) {
00227                                 return m_prefcount->increment();
00228                         }
00229                         return 0;
00230                 }
00231 
00232         long decrement(void) throw() {
00233                         if (m_prefcount) {
00234                                 return m_prefcount->decrement();
00235                         }
00236                         return 0;
00237                 }
00238 
00239         // private data --------------------------------------------------------
00240         threadsafe_counter *    m_prefcount;    // pointer to ref count
00241         T      *m_pT;           // our own (possibly cast) pointer to T
00242 };
00243 
00244 
00245 
00246 #endif  // WAVEPACKET_SMART_PTR_H__
00247