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-2008
    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 <map>
   31: #include <string>
   32: 
   33: namespace stlplus
   34: {
   35: 
   36:   ////////////////////////////////////////////////////////////////////////////////
   37:   // internals
   38: 
   39:   template<typename T> class smart_ptr_holder;
   40: 
   41:   ////////////////////////////////////////////////////////////////////////////////
   42:   // Base class
   43:   ////////////////////////////////////////////////////////////////////////////////
   44: 
   45:   template<typename T, typename C>
   46:   class smart_ptr_base
   47:   {
   48:   public:
   49:     //////////////////////////////////////////////////////////////////////////////
   50:     // member type definitions
   51: 
   52:     typedef T value_type;
   53:     typedef T& reference;
   54:     typedef const T& const_reference;
   55:     typedef C value_copy;
   56: 
   57:     //////////////////////////////////////////////////////////////////////////////
   58:     // constructors and destructors
   59: 
   60:     // create a null pointer
   61:     smart_ptr_base(void);
   62: 
   63:     // create a pointer containing a *copy* of the object using the template parameter C
   64:     // this copy is taken because the pointer class maintains a dynamically allocated object 
   65:     // and the T& may not be (usually is not) dynamically allocated
   66:     explicit smart_ptr_base(const T& data) throw(illegal_copy);
   67: 
   68:     // create a pointer containing a dynamically created object
   69:     // Note: the object must be allocated *by the user* with new
   70:     // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))
   71:     explicit smart_ptr_base(T* data);
   72: 
   73:     // copy constructor implements aliasing so no copy is made
   74:     explicit smart_ptr_base(const smart_ptr_base<T,C>& r);
   75: 
   76:     // destructor decrements the reference count and delete only when the last reference is destroyed
   77:     ~smart_ptr_base(void);
   78: 
   79:     //////////////////////////////////////////////////////////////////////////////
   80:     // logical tests to see if there is anything contained in the pointer since it can be null
   81: 
   82:     // there are two forms:explicit and implicit
   83:     // implicit: if(!r) or if(r)
   84:     // explicit: if(r.null()) or if(r.present())
   85:     operator bool(void) const;
   86:     bool operator!(void) const;
   87:     bool present(void) const;
   88:     bool null(void) const;
   89: 
   90:     //////////////////////////////////////////////////////////////////////////////
   91:     // dereference operators and functions
   92: 
   93:     // dereference the smart pointer to get the object - use in the form *p1
   94:     T& operator*(void) throw(null_dereference);
   95:     const T& operator*(void) const throw(null_dereference);
   96: 
   97:     // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
   98:     T* operator->(void) throw(null_dereference);
   99:     const T* operator->(void) const throw(null_dereference);
  100: 
  101:     //////////////////////////////////////////////////////////////////////////////
  102:     // explicit function forms of the above assignment and dereference operators
  103: 
  104:     // set the value - note that this does a copy using the C template parameter
  105:     void set_value(const T& data) throw(illegal_copy);
  106:     // get the value
  107:     T& value(void) throw(null_dereference);
  108:     const T& value(void) const throw(null_dereference);
  109: 
  110:     // set the pointer
  111:     // deletes the previous pointer and adopts the passed pointer instead
  112:     // Note: the object must be allocated *by the user* with new
  113:     // Warning: it is very easy to break the memory management with this operation
  114:     void set(T* data = 0);
  115:     // get the pointer
  116:     T* pointer(void);
  117:     const T* pointer(void) const;
  118: 
  119:     //////////////////////////////////////////////////////////////////////////////
  120:     // functions to manage aliases
  121: 
  122:     // make this an alias of the passed object
  123:     void alias(const smart_ptr_base<T,C>&);
  124: 
  125:     // test whether two pointers point to the same object(known as aliasing the object)
  126:     // used in the form if(a.aliases(b))
  127:     bool aliases(const smart_ptr_base<T,C>&) const;
  128: 
  129:     // find the number of aliases - used when you need to know whether an
  130:     // object is still referred to from elsewhere (rare!)
  131:     unsigned alias_count(void) const;
  132: 
  133:     // delete the object and make the pointer null - does not make it unique
  134:     // first, so all other pointers to this will be null too
  135:     void clear(void);
  136: 
  137:     // make the pointer unique and null in one step - does not affect other
  138:     // pointers that were pointing to the same object
  139:     void clear_unique(void);
  140: 
  141:     //////////////////////////////////////////////////////////////////////////////
  142:     // functions that involve copying
  143: 
  144:     // these functions use the copy functor passed as the template parameter C
  145:     // to copy the object with the right copy semantics. If the copy functor
  146:     // is no_copy, an exception will be thrown.
  147: 
  148:     // make this pointer unique with respect to any other references to the same object
  149:     // if this pointer is already unique, it does nothing - otherwise it copies the object
  150:     void make_unique(void) throw(illegal_copy);
  151: 
  152:     // make this pointer a unique copy of the parameter
  153:     // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
  154:     void copy(const smart_ptr_base<T,C>&) throw(illegal_copy);
  155: 
  156:   protected:
  157:     smart_ptr_holder<T>* m_holder;
  158: 
  159:   public:
  160:     // internal use only - had to make them public because they need to be
  161:     // accessed by routines that could not be made friends
  162:     void* handle(void) const;
  163:     void make_alias(void* handle);
  164:   };
  165: 
  166:   ////////////////////////////////////////////////////////////////////////////////
  167:   // copy functors implementing the three possible copy semantics
  168: 
  169:   // constructor_copy uses the copy constructor of the object - used for simple types
  170: 
  171:   template <typename T>
  172:   class constructor_copy
  173:   {
  174:   public:
  175:     T* operator() (const T& from) throw()
  176:       {
  177:         return new T(from);
  178:       }
  179:   };
  180: 
  181:   // clone_copy uses the clone method of the object - used for polymorphic types
  182: 
  183:   template <typename T>
  184:   class clone_copy
  185:   {
  186:   public:
  187:     T* operator() (const T& from) throw()
  188:       {
  189:         return from.clone();
  190:       }
  191:   };
  192: 
  193:   // no_copy throws an exception - used for types that cannot be copied
  194: 
  195:   template <typename T>
  196:   class no_copy
  197:   {
  198:   public:
  199:     T* operator() (const T& from) throw(illegal_copy)
  200:       {
  201:         throw illegal_copy("no_copy functor called");
  202:         return 0;
  203:       }
  204:   };
  205: 
  206:   ////////////////////////////////////////////////////////////////////////////////
  207:   // smart_ptr        for simple types and classes which have copy constructors
  208: 
  209:   template <typename T>
  210:   class smart_ptr : public smart_ptr_base<T, constructor_copy<T> >
  211:   {
  212:   public:
  213:     smart_ptr(void) {}
  214:     explicit smart_ptr(const T& data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
  215:     explicit smart_ptr(T* data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
  216:     smart_ptr<T>& operator=(const T& data) {set_value(data); return *this;}
  217:     smart_ptr<T>& operator=(const smart_ptr<T>& r) {alias(r); return *this;}
  218:     ~smart_ptr(void) {}
  219:   };
  220: 
  221:   ////////////////////////////////////////////////////////////////////////////////
  222:   // smart_ptr_clone  for polymorphic class hierarchies which have a clone method
  223: 
  224:   template <typename T>
  225:   class smart_ptr_clone : public smart_ptr_base<T, clone_copy<T> >
  226:   {
  227:   public:
  228:     smart_ptr_clone(void) {}
  229:     explicit smart_ptr_clone(const T& data) : smart_ptr_base<T, clone_copy<T> >(data) {}
  230:     explicit smart_ptr_clone(T* data) : smart_ptr_base<T, clone_copy<T> >(data) {}
  231:     smart_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}
  232:     smart_ptr_clone<T>& operator=(const smart_ptr_clone<T>& r) {alias(r); return *this;}
  233:     ~smart_ptr_clone(void) {}
  234:   };
  235: 
  236:   ////////////////////////////////////////////////////////////////////////////////
  237:   // smart_ptr_nocopy for any class that cannot or should not be copied
  238: 
  239:   template <typename T>
  240:   class smart_ptr_nocopy : public smart_ptr_base<T, no_copy<T> >
  241:   {
  242:   public:
  243:     smart_ptr_nocopy(void) {}
  244:     explicit smart_ptr_nocopy(const T& data) : smart_ptr_base<T, no_copy<T> >(data) {}
  245:     explicit smart_ptr_nocopy(T* data) : smart_ptr_base<T, no_copy<T> >(data) {}
  246:     smart_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}
  247:     smart_ptr_nocopy<T>& operator=(const smart_ptr_nocopy<T>& r) {alias(r); return *this;}
  248:     ~smart_ptr_nocopy(void) {}
  249:   };
  250: 
  251:   ////////////////////////////////////////////////////////////////////////////////
  252: 
  253: } // end namespace stlplus
  254: 
  255: #include "smart_ptr.tpp"
  256: #endif