Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/Referenced

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: Referenced 1029 2004-02-11 20:45:54Z jungd $
00019   $Revision: 1.4 $
00020   $Date: 2004-02-11 15:45:54 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #ifndef _BASE_REFERENCED_
00026 #define _BASE_REFERENCED_
00027 
00028 #include <iostream>
00029 
00030 namespace base {
00031 
00032 /** Base class for intrusively referenced counted objects.
00033     Used by class ref */
00034 class Referenced
00035 {
00036   
00037 public:
00038   Referenced() 
00039     : _refCount(0), onUnreferenceEnabled(false)
00040 #ifdef DEBUG
00041       ,_markedForDestruction(false)
00042 #endif
00043   {
00044 #ifdef DEBUG
00045     // check that *this is not allocated on the stack
00046     //  (assumes stack is above heap in process vm space, and stack grows down)
00047     int onstack;
00048     if ( ((void*)this) > &onstack)
00049       throw std::runtime_error(Exception("Referenced object allocated on the stack! (only Heap allocation allowed)"));
00050 #endif
00051     //if (MemoryTracer::getName((void*)this) != 0) { Logln("Initialized " << MemoryTracer::getName((void*)this) << "+" << base::MemoryTracer::getOffset((void*)this) << " ptr " << ((const void*)this) << " to " << _refCount); }
00052   }
00053       
00054   Referenced(const Referenced& c) 
00055     : _refCount(0), onUnreferenceEnabled(c.onUnreferenceEnabled)
00056 #ifdef DEBUG
00057       ,_markedForDestruction(false)
00058 #endif
00059   {
00060     //if (MemoryTracer::getName((void*)this) != 0) { Logln("Initialized " << MemoryTracer::getName((void*)this) << "+" << base::MemoryTracer::getOffset((void*)this) << " ptr " << ((const void*)this) << " to " << _refCount); }
00061   }  
00062 
00063   /** Increment the reference count by one, indicating that 
00064       this object has another pointer which is referencing it.*/
00065   inline void reference() const 
00066   {
00067     ++_refCount;
00068     //if (MemoryTracer::getName((void*)this) != 0) { Logln("Incremented " << MemoryTracer::getName((void*)this) << "+" << base::MemoryTracer::getOffset((void*)this) << " ptr " << ((const void*)this) << " to " << _refCount); }
00069 #ifdef DEBUG
00070     if (_markedForDestruction) {
00071       std::cerr << "Warning: Object has been re-referenced() after being unreferenced() for the last time (deletion signalled)\n";
00072     }
00073 #endif
00074   }
00075 
00076 
00077   /** Decrement the reference count by one, indicating that 
00078       a pointer to this object is referencing it.  If the
00079       refence count goes to zero, it is assumed that this object
00080       is nolonger referenced and is automatically deleted.*/
00081   inline bool unreference() const 
00082     { 
00083       --_refCount; 
00084       if (onUnreferenceEnabled) 
00085         onUnreference();
00086 
00087       //if (MemoryTracer::getName((void*)this) != 0) { Logln("Decremented " << MemoryTracer::getName((void*)this) << "+" << base::MemoryTracer::getOffset((void*)this) << " ptr " << ((const void*)this) << " to " << _refCount); }
00088       if (_refCount<=0) { 
00089 #ifdef DEBUG
00090         if (_refCount < 0) {
00091           std::cerr << "Object has been unreferenced() too many times!\n";
00092           throw std::runtime_error(Exception("Object has been unreferenced() too many times!"));
00093         }
00094         else {
00095           if (_markedForDestruction) {
00096             return false; // don't destroy twice!
00097           }
00098           else {
00099             _markedForDestruction = true;
00100             //if (MemoryTracer::getName((void*)this) != 0) { Logln("Marked " << MemoryTracer::getName((void*)this) << "+" << base::MemoryTracer::getOffset((void*)this) << " ptr " << ((const void*)this) << " for deletion"); }
00101             return true; // signal caller to delete us
00102           }
00103         }
00104 #else
00105         return true; // signal caller to delete us
00106 #endif
00107       } // _refCount<=0
00108       return false;
00109     }
00110 
00111   /** Return the number pointers currently referencing this object. */
00112   inline const int referenceCount() const { return _refCount; }
00113 
00114   /** If enabled, each call to unreference() will also call virtual method onUnreference() */
00115   void enableOnUnreferenceCall(bool enabled) { onUnreferenceEnabled=enabled; }
00116 
00117   /** Called by unreference() if enabled via enableOnUnreferenceCall(true).  
00118    *  Typically overridden in subclasses that wish to know about unreference() calls - for example
00119    *  to handle manually breaking cyclic references
00120    */
00121   virtual void onUnreference() const {}
00122 
00123 
00124   
00125   virtual ~Referenced() 
00126   {
00127 #ifdef DEBUG
00128     if (_refCount > 0) {
00129       std::cerr << "Object has been destructed with outstanding references.\n";
00130       throw std::runtime_error(Exception("Object has been destructed with outstanding references."));
00131     }
00132 #endif
00133   }
00134   
00135 protected:
00136   mutable int _refCount;
00137   bool onUnreferenceEnabled;
00138 #ifdef DEBUG
00139   mutable bool _markedForDestruction; ///< true if _refCount has dropped to 0 after being non-zero
00140 #endif
00141 };
00142 
00143 };
00144 
00145 #endif

Generated on Thu Jul 29 15:56:12 2004 for OpenSim by doxygen 1.3.6