Aegis  4.25.D505
/home/archives/aegis/branch.4/branch.25/delta28933.505/common/ac/shared_ptr/aegis.h
Go to the documentation of this file.
00001 //
00002 //      aegis - project change supervisor
00003 //      Copyright (C) 2007, 2008, 2012 Peter Miller
00004 //
00005 //      This program is free software; you can redistribute it and/or modify
00006 //      it under the terms of the GNU General Public License as published by
00007 //      the Free Software Foundation; either version 3 of the License, or
00008 //      (at your option) any later version.
00009 //
00010 //      This program is distributed in the hope that it will be useful,
00011 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 //      GNU General Public License for more details.
00014 //
00015 //      You should have received a copy of the GNU General Public License
00016 //      along with this program. If not, see
00017 //      <http://www.gnu.org/licenses/>.
00018 //
00019 
00020 #ifndef COMMON_AC_SHARED_PTR_AEGIS_H
00021 #define COMMON_AC_SHARED_PTR_AEGIS_H
00022 
00023 #include <common/ac/assert.h>
00024 
00035 template<class T>
00036 class aegis_shared_ptr
00037 {
00038 private:
00050     long *reference_count;
00051 
00057     T *subject;
00058 
00059 public:
00064     bool
00065     valid()
00066         const
00067     {
00068         return
00069             (
00070                 (reference_count != 0)
00071             ?
00072                 (*reference_count > 0 && subject != 0)
00073             :
00074                 (subject == 0)
00075             );
00076     }
00077 
00085     ~aegis_shared_ptr()
00086     {
00087         assert(valid());
00088         if (reference_count)
00089         {
00090             --*reference_count;
00091             if (*reference_count <= 0)
00092             {
00093                 delete subject;
00094                 subject = 0;
00095                 delete reference_count;
00096                 reference_count = 0;
00097             }
00098         }
00099     }
00100 
00107     void
00108     swap(aegis_shared_ptr &rhs)
00109     {
00110         assert(valid());
00111         assert(rhs.valid());
00112         long *temp_reference_count = reference_count;
00113         T *temp_subject = subject;
00114         reference_count = rhs.reference_count;
00115         subject = rhs.subject;
00116         rhs.reference_count = temp_reference_count;
00117         rhs.subject = temp_subject;
00118     }
00119 
00123     void
00124     reset()
00125     {
00126         // swap with a NULL pointer
00127         aegis_shared_ptr tmp;
00128         this->swap(tmp);
00129     }
00130 
00134     aegis_shared_ptr() :
00135         reference_count(0),
00136         subject(0)
00137     {
00138         assert(valid());
00139     }
00140 
00148     template<class Y> explicit
00149     aegis_shared_ptr(Y *rhs) :
00150         reference_count(0),
00151         subject(0)
00152     {
00153         assert(valid());
00154         if (rhs)
00155         {
00156             reference_count = new long(1);
00157             subject = rhs;
00158         }
00159         assert(valid());
00160     }
00161 
00168     aegis_shared_ptr(const aegis_shared_ptr &rhs) :
00169         reference_count(0),
00170         subject(0)
00171     {
00172         assert(rhs.valid());
00173         if (rhs.subject)
00174         {
00175             assert(rhs.reference_count);
00176             reference_count = rhs.reference_count;
00177             subject = rhs.subject;
00178             ++*reference_count;
00179         }
00180         assert(valid());
00181     }
00182 
00183     template <class Y> friend class aegis_shared_ptr;
00184 
00191     template<class Y>
00192     aegis_shared_ptr(const aegis_shared_ptr<Y> &rhs) :
00193         reference_count(0),
00194         subject(0)
00195     {
00196         assert(rhs.valid());
00197         if (rhs.subject)
00198         {
00199             assert(rhs.reference_count);
00200             reference_count = rhs.reference_count;
00201             subject = rhs.subject;
00202             ++*reference_count;
00203         }
00204         assert(valid());
00205     }
00206 
00213     aegis_shared_ptr &
00214     operator=(const aegis_shared_ptr &rhs)
00215     {
00216         assert(valid());
00217         assert(rhs.valid());
00218         if (this != &rhs)
00219         {
00220             // In case you haven't seen the swap() technique to
00221             // implement copy assignment before, here's what it does:
00222             //
00223             // 1) Create a temporary aegis_shared_ptr<> instance via the
00224             //    copy constructor, thereby increasing the reference
00225             //    count of the source object.
00226             //
00227             // 2) Swap the internal object pointers of *this and the
00228             //    temporary aegis_shared_ptr<>.  After this step, *this
00229             //    already contains the new pointer, and the old pointer
00230             //    is now managed by temp.
00231             //
00232             // 3) The destructor of temp is executed, thereby
00233             //    unreferencing the old object pointer.
00234             //
00235             // This technique is described in Herb Sutter's "Exceptional
00236             // C++", and has a number of advantages over conventional
00237             // approaches:
00238             //
00239             // - Code reuse by calling the copy constructor.
00240             // - Strong exception safety for free.
00241             // - Self assignment is handled implicitly.
00242             // - Simplicity.
00243             // - It just works and is hard to get wrong; i.e. you can
00244             //   use it without even thinking about it to implement
00245             //   copy assignment where ever the object data is managed
00246             //   indirectly via a pointer, which is very common.
00247             //
00248             aegis_shared_ptr temp(rhs);
00249             this->swap(temp);
00250             assert(valid());
00251             assert(rhs.valid());
00252         }
00253         return *this;
00254     }
00255 
00262     template<class Y>
00263     aegis_shared_ptr &
00264     operator=(const aegis_shared_ptr<Y> &rhs)
00265     {
00266         assert(valid());
00267         assert(rhs.valid());
00268         if (this != (aegis_shared_ptr *)&rhs)
00269         {
00270             aegis_shared_ptr tmp(rhs);
00271             this->swap(tmp);
00272             assert(valid());
00273             assert(rhs.valid());
00274         }
00275         return *this;
00276     }
00277 
00278 #if 0
00279 
00285     template<class Y> explicit
00286     aegis_shared_ptr(std::auto_ptr<Y> &rhs) :
00287         reference_count(0),
00288         subject(0)
00289     {
00290         Y *tmp = r.get();
00291         if (tmp)
00292         {
00293             reference_count = new long(1);
00294             subject = tmp;
00295         }
00296         assert(valid());
00297     }
00298 
00305     template<class Y>
00306     aegis_shared_ptr &
00307     operator=(std::auto_ptr<Y> &rhs)
00308     {
00309         assert(valid());
00310         reset();
00311         if (tmp)
00312         {
00313             reference_count = new long(1);
00314             subject = tmp;
00315         }
00316         assert(valid());
00317         return *this;
00318     }
00319 
00320 #endif
00321 
00329     T &
00330     operator*()
00331         const
00332     {
00333         assert(subject != 0);
00334         return *subject;
00335     }
00336 
00344     T *
00345     operator->()
00346         const
00347     {
00348         assert(subject != 0);
00349         return subject;
00350     }
00351 
00355     T *
00356     get()
00357         const
00358     {
00359         return subject;
00360     }
00361 
00366     operator bool()
00367         const
00368     {
00369         return (subject != 0);
00370     }
00371 
00376     bool
00377     operator!()
00378         const
00379     {
00380         return (subject == 0);
00381     }
00382 
00383     inline bool
00384     operator==(const aegis_shared_ptr &rhs)
00385         const
00386     {
00387         return (subject == rhs.get());
00388     }
00389 
00390     template<class U>
00391     inline bool
00392     operator==(const aegis_shared_ptr<U> &rhs)
00393         const
00394     {
00395         return (subject == rhs.get());
00396     }
00397 
00398     inline bool
00399     operator!=(aegis_shared_ptr &rhs)
00400         const
00401     {
00402         return (subject != rhs.get());
00403     }
00404 
00405     template<class U>
00406     inline bool
00407     operator!=(aegis_shared_ptr<U> &rhs)
00408         const
00409     {
00410         return (subject != rhs.get());
00411     }
00412 
00413     inline bool
00414     operator<(aegis_shared_ptr &rhs)
00415         const
00416     {
00417         return (subject < rhs.get());
00418     }
00419 
00420     template<class U>
00421     inline bool
00422     operator<(aegis_shared_ptr<U> &rhs)
00423         const
00424     {
00425         return (subject < rhs.get());
00426     }
00427 };
00428 
00429 #endif // COMMON_AC_SHARED_PTR_AEGIS_H
00430 // vim: set ts=8 sw=4 et :