containers/smart_ptr.hpp

    1: #ifndef STLPLUS_SMART_PTR
    2: #define STLPLUS_SMART_PTR
    3: ////////////////////////////////////////////////////////////////////////////////
    4: 
    5: //   Author:    Andy Rushton
    6: //   Copyright: (c) Southampton University 1999-2004
    7: //              (c) Andy Rushton           2004-2009
    8: //   License:   BSD License, see ../docs/license.html
    9: 
   10: //   A smart pointer is a memory-managing pointer to an object. If you like, it
   11: //   is a zero-dimensional container.
   12: 
   13: //   Assignment of smart pointers result in multiple aliases of the same object.
   14: //   The term alias is used to differentiate from conventional pointers because
   15: //   the semantics are different.
   16: 
   17: //   Aliases can be turned into copies if the pointed-to class supports copying.
   18: 
   19: //   The base class is smart_ptr_base which defines the common interface. Then
   20: //   there are three subclasses which have the same interface but different copy
   21: //   semantics:
   22: 
   23: //   - smart_ptr        for simple types and classes which have copy constructors
   24: //   - smart_ptr_clone  for polymorphic class hierarchies which are copied using a clone method
   25: //   - smart_ptr_nocopy for any class that cannot or should not be copied
   26: 
   27: ////////////////////////////////////////////////////////////////////////////////
   28: #include "containers_fixes.hpp"
   29: #include "exceptions.hpp"
   30: #include "copy_functors.hpp"
   31: #include <map>
   32: #include <string>
   33: 
   34: namespace stlplus
   35: {
   36: 
   37:   ////////////////////////////////////////////////////////////////////////////////
   38:   // internals
   39: 
   40:   template<typename T> class smart_ptr_holder;
   41: 
   42:   ////////////////////////////////////////////////////////////////////////////////
   43:   // Base class
   44:   ////////////////////////////////////////////////////////////////////////////////
   45: 
   46:   template<typename T, typename C>
   47:   class smart_ptr_base
   48:   {
   49:   public:
   50:     //////////////////////////////////////////////////////////////////////////////
   51:     // member type definitions
   52: 
   53:     typedef T value_type;
   54:     typedef T& reference;
   55:     typedef const T& const_reference;
   56:     typedef C value_copy;
   57: 
   58:     //////////////////////////////////////////////////////////////////////////////
   59:     // constructors and destructors
   60: 
   61:     // create a null pointer
   62:     smart_ptr_base(void);
   63: 
   64:     // create a pointer containing a *copy* of the object using the template parameter C
   65:     // this copy is taken because the pointer class maintains a dynamically allocated object
   66:     // and the T& may not be (usually is not) dynamically allocated
   67:     explicit smart_ptr_base(const T& data) throw(illegal_copy);
   68: 
   69:     // create a pointer containing a dynamically created object
   70:     // Note: the object must be allocated *by the user* with new
   71:     // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))
   72:     explicit smart_ptr_base(T* data);
   73: 
   74:     // copy constructor implements aliasing so no copy is made
   75:     // note that the copy constructor should NOT be explicit, as this breaks
   76:     // the returning of pointer objects from functions (at least within GCC 4.4)
   77:     smart_ptr_base(const smart_ptr_base<T,C>& r);
   78: 
   79:     // assignment operator - required, else the output of GCC suffers segmentation faults
   80:     smart_ptr_base<T,C>& operator=(const smart_ptr_base<T,C>& r);
   81: 
   82:     // destructor decrements the reference count and delete only when the last reference is destroyed
   83:     ~smart_ptr_base(void);
   84: 
   85:     //////////////////////////////////////////////////////////////////////////////
   86:     // logical tests to see if there is anything contained in the pointer since it can be null
   87: 
   88:     // there are two forms:explicit and implicit
   89:     // implicit: if(!r) or if(r)
   90:     // explicit: if(r.null()) or if(r.present())
   91:     operator bool(void) const;
   92:     bool operator!(void) const;
   93:     bool present(void) const;
   94:     bool null(void) const;
   95: 
   96:     //////////////////////////////////////////////////////////////////////////////
   97:     // dereference operators and functions
   98: 
   99:     // dereference the smart pointer to get the object - use in the form *p1
  100:     T& operator*(void) throw(null_dereference);
  101:     const T& operator*(void) const throw(null_dereference);
  102: 
  103:     // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
  104:     T* operator->(void) throw(null_dereference);
  105:     const T* operator->(void) const throw(null_dereference);
  106: 
  107:     //////////////////////////////////////////////////////////////////////////////
  108:     // explicit function forms of the above assignment and dereference operators
  109: 
  110:     // set the value - note that this does a copy using the C template parameter
  111:     void set_value(const T& data) throw(illegal_copy);
  112:     // get the value
  113:     T& value(void) throw(null_dereference);
  114:     const T& value(void) const throw(null_dereference);
  115: 
  116:     // set the pointer
  117:     // deletes the previous pointer and adopts the passed pointer instead
  118:     // Note: the object must be allocated *by the user* with new
  119:     // Warning: it is very easy to break the memory management with this operation
  120:     void set(T* data = 0);
  121:     // get the pointer
  122:     T* pointer(void);
  123:     const T* pointer(void) const;
  124: 
  125:     //////////////////////////////////////////////////////////////////////////////
  126:     // functions to manage aliases
  127: 
  128:     // make this an alias of the passed object
  129:     void alias(const smart_ptr_base<T,C>&);
  130: 
  131:     // test whether two pointers point to the same object(known as aliasing the object)
  132:     // used in the form if(a.aliases(b))
  133:     bool aliases(const smart_ptr_base<T,C>&) const;
  134: 
  135:     // find the number of aliases - used when you need to know whether an
  136:     // object is still referred to from elsewhere (rare!)
  137:     unsigned alias_count(void) const;
  138: 
  139:     // delete the object and make the pointer null - does not make it unique
  140:     // first, so all other pointers to this will be null too
  141:     void clear(void);
  142: 
  143:     // make the pointer unique and null in one step - does not affect other
  144:     // pointers that were pointing to the same object
  145:     void clear_unique(void);
  146: 
  147:     //////////////////////////////////////////////////////////////////////////////
  148:     // functions that involve copying
  149: 
  150:     // these functions use the copy functor passed as the template parameter C
  151:     // to copy the object with the right copy semantics. If the copy functor
  152:     // is no_copy, an exception will be thrown.
  153: 
  154:     // make this pointer unique with respect to any other references to the same object
  155:     // if this pointer is already unique, it does nothing - otherwise it copies the object
  156:     void make_unique(void) throw(illegal_copy);
  157: 
  158:     // make this pointer a unique copy of the parameter
  159:     // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
  160:     void copy(const smart_ptr_base<T,C>&) throw(illegal_copy);
  161: 
  162:   protected:
  163:     smart_ptr_holder<T>* m_holder;
  164: 
  165:   public:
  166:     // internal use only - had to make them public because they need to be
  167:     // accessed by routines that could not be made friends
  168:     smart_ptr_holder<T>* _handle(void) const;
  169:     void _make_alias(smart_ptr_holder<T>* handle);
  170:   };
  171: 
  172:   ////////////////////////////////////////////////////////////////////////////////
  173:   // smart_ptr        for simple types and classes which have copy constructors
  174: 
  175:   template <typename T>
  176:   class smart_ptr : public smart_ptr_base<T, constructor_copy<T> >
  177:   {
  178:   public:
  179:     smart_ptr(void) {}
  180:     explicit smart_ptr(const T& data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
  181:     explicit smart_ptr(T* data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
  182:     smart_ptr<T>& operator=(const T& data) {set_value(data); return *this;}
  183:     smart_ptr<T>& operator=(T* data) {set(data); return *this;}
  184:     ~smart_ptr(void) {}
  185:   };
  186: 
  187:   ////////////////////////////////////////////////////////////////////////////////
  188:   // smart_ptr_clone  for polymorphic class hierarchies which have a clone method
  189: 
  190:   template <typename T>
  191:   class smart_ptr_clone : public smart_ptr_base<T, clone_copy<T> >
  192:   {
  193:   public:
  194:     smart_ptr_clone(void) {}
  195:     explicit smart_ptr_clone(const T& data) : smart_ptr_base<T, clone_copy<T> >(data) {}
  196:     explicit smart_ptr_clone(T* data) : smart_ptr_base<T, clone_copy<T> >(data) {}
  197:     smart_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}
  198:     smart_ptr_clone<T>& operator=(T* data) {set(data); return *this;}
  199:     ~smart_ptr_clone(void) {}
  200:   };
  201: 
  202:   ////////////////////////////////////////////////////////////////////////////////
  203:   // smart_ptr_nocopy for any class that cannot or should not be copied
  204: 
  205:   template <typename T>
  206:   class smart_ptr_nocopy : public smart_ptr_base<T, no_copy<T> >
  207:   {
  208:   public:
  209:     smart_ptr_nocopy(void) {}
  210:     explicit smart_ptr_nocopy(const T& data) : smart_ptr_base<T, no_copy<T> >(data) {}
  211:     explicit smart_ptr_nocopy(T* data) : smart_ptr_base<T, no_copy<T> >(data) {}
  212:     smart_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}
  213:     smart_ptr_nocopy<T>& operator=(T* data) {set(data); return *this;}
  214:     ~smart_ptr_nocopy(void) {}
  215:   };
  216: 
  217:   ////////////////////////////////////////////////////////////////////////////////
  218: 
  219: } // end namespace stlplus
  220: 
  221: #include "smart_ptr.tpp"
  222: #endif