00001 /* lkptr.h (C) 2007 adolfo@di-mare.com */ 00002 00003 /** \file lkptr.h 00004 \brief simple reference LinKed PoinTeR. 00005 00006 \author Adolfo Di Mare <adolfo@di-mare.com> 00007 \date 2007 00008 */ 00009 00010 /// MOD this when your compiler does compile this correctly. 00011 #undef COMPILER_lkptr 00012 00013 #ifdef _MSC_VER 00014 #if _MSC_VER >= 1300 // .net Microsoft Visual Studio C++ 00015 #define COMPILER_lkptr 00016 #endif 00017 #endif 00018 00019 #ifdef __BORLANDC__ // Borland C++ 00020 #if (__BORLANDC__ <= 0x0410) // BC++ v3.1 or earlier 00021 #undef COMPILER_lkptr 00022 #endif 00023 #endif 00024 00025 #ifndef COMPILER_lkptr 00026 #error Compiler not yet supported // emit error 00027 #define lkptr_h // avoid file inclussion || compilation 00028 #endif 00029 00030 #ifndef lkptr_h 00031 #define lkptr_h ///< Avoid multiple file inclusion 00032 00033 template <class X> class lkptr; // class declaration follows 00034 00035 /** These smart pointer share the object they point to. 00036 Only after the last pointer releases its reference will the object be deleted. 00037 - Whenever the object will be changed by one of the pointers, all the 00038 other pointers will also see the change. 00039 - The implementation stores three pointers for every \c lkptr, 00040 but does not allocate anything on the free store. 00041 - Every \c lkptr is implemented using 3 internal pointers which 00042 makes it 3 times as big as a regular pointer. In exchange, 00043 automatic garbage collection is provided by the C++ 00044 constructor - destructor protocol of execution. 00045 - These pointers are double linked together. When only one pointer 00046 is in the chain, then the object will be deleted if the pointer 00047 releases it. Otherwise, the object will not be deleted because 00048 the other pointers in the chain are still referencing it. 00049 - These pointers are not intrusive, because they do not need an 00050 extra field in the pointed object to keep track of how many 00051 pointers reference the same object. 00052 - These pointers do not allocate extra memory to keep track of the 00053 reference count, because the linked list itself binds together 00054 all pointers that reference the same object. 00055 - A diagram for the pointer chain is shown in the documentation for 00056 method \c ok(). 00057 - Many of the pointer operators will never throw exceptions (hence 00058 the \c "throw()" especification in the method signature). 00059 - Memory leaks are extremely rare. Reference counting/linking can 00060 leak in the case of circular references (i.e., when the pointed 00061 object itself contains a counted/linked pointer, which points 00062 to an object that contains the original counted/linked pointer). 00063 - These pointers cannot be used in ROM memory because they modify 00064 each other when double linking, even if they are \c const. 00065 00066 \par Usage: 00067 \code 00068 void foo() { 00069 lkptr<AnyClass> p(new AnyClass); // "p" is one smart-pointer 00070 lkptr<AnyClass> q; // "q" is the other smart-pointer 00071 00072 p->DoSomething(); // no syntax change when using pointers 00073 q = p; // share the object 00074 q->Change(); // both "*p" && "*q" get changed 00075 p = q; // both still point to the same object 00076 lkptr<AnyClass> r = p; // The 3 of them share the same object 00077 00078 // delete p; // No need to worry about destruction 00079 // delete q; // the lkptr<> destructor will handle deletions for you. 00080 // delete r; 00081 } 00082 \endcode 00083 00084 - This work is based on Sharon's paper: 00085 - "Smart Pointers - What, Why, Which?" 00086 - http://ootips.org/yonat/4dev/smart-pointers.html 00087 - Yonat Sharon <yonat@ootips.org> 00088 - 1999. 00089 */ 00090 template <class X> 00091 class lkptr { 00092 private: // Rep fields have the "m_" prefix 00093 X * m_ptr; ///< Pointer to referenced object (can be a \c NULL pointer). 00094 lkptr * m_prev; ///< Next in pointer chain. 00095 lkptr * m_next; ///< Previous in pointer chain. 00096 public: 00097 typedef X element_type; ///< Standard name for the pointed object. 00098 00099 /// Default constructor and constructor from a regular pointer. 00100 explicit lkptr(X* p = 0) throw() : m_ptr(p) { m_prev = m_next = this; } 00101 ~lkptr() { fast_release(); } ///< Destructor. Delete only if last reference. 00102 00103 /// Copy constructor: share the object with other pointers. 00104 lkptr( const lkptr& r ) throw() { acquire( const_cast<lkptr*>( &r ) ); } 00105 /// Copy operator: share the object with other pointers. 00106 lkptr& operator=( const lkptr& r ) { 00107 if (this != &r) { // avoid self - anhilation 00108 fast_release(); // all the fields are in a broken state 00109 acquire( const_cast<lkptr<X>*>( &r ) ); // r's chain fields will be changed 00110 } 00111 return *this; 00112 /* NOTE: 00113 A lkptr<D> will be implicitly converted to a lkptr<B> 00114 if a D* can be converted to a B*. ( D ~~ Derived ... B ~~ Base ) 00115 */ 00116 } 00117 00118 // Pointer access operators (these never throw exceptions) 00119 X* get() const throw() { return m_ptr; } ///< Returns a pointer to referenced object. 00120 X& value() const throw() { return *m_ptr; } ///< Returns the referenced object. 00121 X& operator*() const throw() { return *m_ptr; } ///< Returns the referenced object. 00122 X* operator->() const throw() { return m_ptr; } ///< Returns a pointer to referenced object. 00123 operator X* () const throw() { return m_ptr; } ///< Returns a pointer to referenced object. 00124 00125 /// Returns \c true if the object pointed is null and \c false otherwise. 00126 bool isNull() const throw() { return m_ptr == 0; } 00127 00128 /// Return \c "true" when only one pointer references the object. 00129 bool unique() const throw() { return ( m_prev == this ); } 00130 00131 /// Returns how many pointers are sharing the object referenced by \c "this". 00132 int refs() const throw(); 00133 00134 /// Releases the object. 00135 /// - Before: If this was the last reference, it also deletes the referenced object. 00136 /// - After: The pointed to object becomes \c NULL. 00137 /// - After: Equivalent to \c reset(0). 00138 void release() { 00139 fast_release(); // all the fields are in a broken state 00140 m_prev = m_next = this; // restore invariant: unique in chain 00141 m_ptr = 0; 00142 } 00143 00144 /// Resets the pointer so that it will point to \c "p". 00145 /// - Before: If this was the last reference, it also deletes the referenced object. 00146 /// - Before: \c "p==0" is a valid argument (\c NULL is ok). 00147 /// - After: The object pointed by \c "p" gets to be own by \c "this". 00148 void reset(X* p=0) { 00149 if (m_ptr == p) { 00150 return; // avoid self - anhilation 00151 } 00152 fast_release(); // all the fields are in a broken state 00153 m_prev = m_next = this; // restore invariant: unique in chain 00154 m_ptr = p; 00155 } 00156 00157 bool ok() const throw(); 00158 template <class X> friend bool check_ok( const lkptr<X>& p ) throw(); 00159 00160 private: 00161 /// Makes \c this->m_ptr point to \c r.m_ptr. 00162 /// - Insert \c "this" after \c "r" in the double chained pointer list. 00163 /// - If called after \c fast_release() will restore the invariant into \c "this". 00164 /// - Will link (this <--> r) even when r->m_ptr is a \c NULL pointer. 00165 void acquire(lkptr* r) throw() { 00166 m_ptr = r->m_ptr; // reference r's object 00167 m_next = r->m_next; 00168 m_next->m_prev = this; // 4 assignments to change the 4 next+prev chain pointers 00169 m_prev = r; 00170 r->m_next = this; 00171 // To double link with the list, "*r" must be changed. But the whole 00172 // implementation is easier if "*r" is const. 00173 } 00174 00175 /// Releases the object. 00176 /// - If \c this->m_ptr is the last reference, it also deletes the object. 00177 /// - Leaves all the fields in \c "this" in a broken state. 00178 /// - Caller must ensure that all the fields get good values after invocation. 00179 void fast_release() { 00180 if ( m_prev == this ) { // auto-linked ==> unique() 00181 if ( m_ptr!=0 ) { 00182 delete m_ptr; // this could throw an exception 00183 } 00184 } 00185 else { // ! unique() ==> unlink from pointer chain 00186 m_prev->m_next = m_next; 00187 m_next->m_prev = m_prev; 00188 } 00189 // leaves all the fields in a broken state: 00190 // m_prev = m_next = this; // set-all to nil pointer 00191 // m_ptr = 0; 00192 } 00193 00194 // clase usada para probar \c lkptr. 00195 template <class X> friend class test_lkptr; 00196 }; // class lkptr 00197 00198 /// <code> (p == q) </code> ??? 00199 template <class X> 00200 bool operator== ( const lkptr<X> & p, const lkptr<X> & q ) { 00201 return p.get() == q.get(); 00202 } 00203 00204 /// <code> (p != q) </code> ??? 00205 template <class X> 00206 bool operator!= ( const lkptr<X> & p, const lkptr<X> & q ) { 00207 return ! (p == q); 00208 } 00209 00210 template <class X> 00211 int lkptr<X>::refs() const throw() { 00212 int n = 1; // count "this" 00213 const lkptr* q = this->m_next; 00214 while (q != this) { // while´s can´t be inlined 00215 q = q->m_next; 00216 ++n; 00217 } 00218 return n; 00219 } 00220 00221 /// Verifies the invariant for class \c lkptr<X>. 00222 /// \see lkptr<X>::ok(). 00223 template <class X> 00224 inline bool check_ok( const lkptr<X>& p ) throw() { return p.ok(); } 00225 00226 /** Verifies the invariant for class \c lkptr<X>. 00227 - Returns \c "true" when \c "p" contains a correct value. 00228 - It could return \c "true" even when it's value is corrupted. 00229 - it could never return if the value in \c "p" is corrupted. 00230 00231 \par Rep: Description with words. 00232 - Field \c "m_ptr" is the pointer to the referenced object. 00233 - All pointers that point to the same object are linked together. 00234 - The list is double linked to allow for O(1) insertion and removal. 00235 - There is no "first" or "last" element in the list. What it is 00236 important is to be "in" the list, not which position in it a 00237 particular \c lkptr<X> occupies. 00238 00239 \par Rep: Class diagram. 00240 \code 00241 <=================================> <=============> 00242 | p1 p2 p3 | | p4 | 00243 | +-+-+ +-+-+ +-+-+ | | +-+-+ | 00244 <===>|*|*|<===>|*|*|<===>|*|*|<===> <===>|*|*|<===> 00245 +-+-+ +-+-+ +-+-+ +-+-+ 00246 | * | | * | | * | | * | 00247 +-|-+ +-|-+ +-|-+ +-|-+ 00248 | | | | 00249 \|/ \|/ \|/ \|/ 00250 +----------------------+ +----------------------+ 00251 | Shared object | | Lonely Object | 00252 +----------------------+ +----------------------+ 00253 \endcode 00254 00255 \code 00256 +--------+-------+ "m_ptr" points to the object 00257 | m_prev | | 00258 +--------+ m_ptr + 00259 | m_next | | "m_next" is next in chain 00260 +--------+-------+ "m_prev" is previous in chain 00261 \endcode 00262 00263 \par The invariant: Description with words. 00264 */ 00265 template <class X> 00266 bool lkptr<X>::ok() const throw() { 00267 { // check a single element double linked chain 00268 if ( (m_next==this) && (m_prev==this) ) { /* Ok */ } 00269 else if ( (m_next==this) || (m_prev==this) ) { 00270 return false; // because one of them must be a broken link 00271 /// - Invariant (1) (broken link): A unique pointer should be self-linked with 00272 /// both \c m_next && \c m_prev pointing to itself (\c this). 00273 } 00274 } 00275 00276 { // check the double linked chain 00277 const lkptr* q = this; 00278 do { 00279 if ( (q == q->m_next->m_prev) && (q == q->m_prev->m_next) ) { /* Ok */ } 00280 else { 00281 return false; 00282 /// - Invariant (2) (broken link): the double linked pointer can never be broken. 00283 } 00284 if (this->m_ptr == q->m_ptr) { /* Ok */ } 00285 else { 00286 return false; 00287 /// - Invariant (3) (broken m_ptr): Every pointer in the chain should reference 00288 /// the same object. 00289 } 00290 q = q->m_next; 00291 } while (q != this); 00292 } 00293 00294 // This "YES" style of programming makes it easier to define the invariant 00295 // in positive terms. 00296 // - The "else" statement are executed when the invariant is broken. 00297 00298 { // check that the pointed object is correct 00299 #if 0 // NOT implemented 00300 // WHY? To avoid forcing the pointed type to have a check_ok() function 00301 bool check_ok( const X& ); // forward declaration 00302 if ( check_ok( * m_ptr ) ) { /* Ok */ } 00303 else { 00304 return false; /// - Invariant (4) (corrupt pointed object) 00305 } 00306 #endif 00307 } 00308 00309 if ( m_ptr==0 ) { // Check that the null pointer is in its own chain 00310 #if 0 // NOT implemented 00311 // WHY? It really does no harm that some null pointers are linked together. 00312 if ( (m_next==this) && (m_prev==this) ) { /* Ok */ } 00313 else { 00314 return false; 00315 /// - Invariant (5) (auto-link): A \c NULL pointer should be self-linked with 00316 /// both \c m_next && \c m_prev pointing to itself (\c this). 00317 } 00318 #endif 00319 } 00320 00321 return true; 00322 } 00323 00324 #endif // lkptr_h 00325 #undef COMPILER_lkptr 00326 00327 // EOF: lkptr.h
1.4.7