lkptr.h

Ir a la documentación de este archivo.
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

Generado el Sat Jul 7 19:11:55 2007 para Implementacion de la clase Arbol_Rojinegro por  doxygen 1.4.7