smart_ptr.hpp

    1: #ifndef SMART_PTR_HPP
    2: #define SMART_PTR_HPP
    3: /*------------------------------------------------------------------------------
    4: 
    5:   Author:    Andy Rushton and Daniel Milton
    6:   Copyright: (c) Andy Rushton, 2004; Daniel Milton 2005
    7:   License:   BSD License, see ../docs/license.html
    8: 
    9:   Dan Milton: three simple pointer containers with single level access:
   10:     - simple_ptr for simple types and classes
   11:     - simple_ptr_clone for polymorphic class hierarchies
   12:     - simple_ptr_nocopy for any class that cannot or should no be copied
   13: 
   14:   Andy Rushton: three smart pointer containers with two-layer access:
   15:     - smart_ptr for simple types and classes
   16:     - smart_ptr_clone for polymorphic class hierarchies
   17:     - smart_ptr_nocopy for any class that cannot or should no be copied
   18: 
   19:   ------------------------------------------------------------------------------*/
   20: #include "os_fixes.hpp"
   21: #include "exceptions.hpp"
   22: #include "persistent.hpp"
   23: #include "textio.hpp"
   24: #include <map>
   25: #include <string>
   26: 
   27: ////////////////////////////////////////////////////////////////////////////////
   28: ////////////////////////////////////////////////////////////////////////////////
   29: // Simple pointer class
   30: ////////////////////////////////////////////////////////////////////////////////
   31: ////////////////////////////////////////////////////////////////////////////////
   32: 
   33: template<typename T>
   34: class simple_ptr
   35: {
   36: public:
   37:   //////////////////////////////////////////////////////////////////////////////
   38:   // member type definitions
   39: 
   40:   typedef T value_type;
   41:   typedef T& reference;
   42:   typedef const T& const_reference;
   43: 
   44:   //////////////////////////////////////////////////////////////////////////////
   45:   // constructors, assignments and destructors
   46: 
   47:   // create a null pointer
   48:   simple_ptr(void);
   49: 
   50:   // create a pointer containing a *copy* of the object
   51:   // this copy is taken because the pointer class maintains a dynamically allocated object 
   52:   // and the T& may not be (usually is not) dynamically allocated
   53:   // constructor form
   54:   simple_ptr(const T& data);
   55:   // assignment form for an already-constructed smart-pointer
   56:   simple_ptr<T>& operator=(const T& data);
   57: 
   58:   // copy constructor implements counted referencing - no copy is made
   59:   simple_ptr(const simple_ptr<T>& r);
   60:   // assignment of smart pointers implement counted referencing - no copy is made
   61:   simple_ptr<T>& operator=(const simple_ptr<T>&);
   62: 
   63:   // create a pointer containing a dynamically created object
   64:   // Note: the object must be allocated *by the user* with new
   65:   // constructor form - must be called in the form simple_ptr<type> x(new type(args))
   66:   explicit simple_ptr(T* data);
   67:   // assignment form
   68:   simple_ptr<T>& operator= (T* data);
   69: 
   70:   // destructor decrements the reference count and delete only when the last reference is destroyed
   71:   ~simple_ptr(void);
   72: 
   73:   //////////////////////////////////////////////////////////////////////////////
   74:   // logical tests to see if there is anything contained in the pointer since it can be null
   75: 
   76:   // there are two forms:explicit and implicit
   77:   // implicit: if(!r) or if(r)
   78:   // explicit: if(r.null()) or if(r.present())
   79:   operator bool(void) const;
   80:   bool operator!(void) const;
   81:   bool present(void) const;
   82:   bool null(void) const;
   83: 
   84:   //////////////////////////////////////////////////////////////////////////////
   85:   // dereference operators and functions
   86: 
   87:   // dereference the smart pointer to get the object - use in the form *p1
   88:   T& operator*(void) throw(null_dereference);
   89:   const T& operator*(void) const throw(null_dereference);
   90: 
   91:   // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
   92:   T* operator->(void) throw(null_dereference);
   93:   const T* operator->(void) const throw(null_dereference);
   94: 
   95:   //////////////////////////////////////////////////////////////////////////////
   96:   // explicit function forms of the above assignment and dereference operators
   97: 
   98:   // set the value
   99:   void set_value(const T& data);
  100:   // get the value
  101:   T& value(void) throw(null_dereference);
  102:   const T& value(void) const throw(null_dereference);
  103: 
  104:   // set the pointer
  105:   // deletes the previous pointer and adopts the passed pointer instead
  106:   // Note: the object must be allocated *by the user* with new
  107:   // Warning: it is very easy to break the memory management with this operation
  108:   void set(T* data = 0);
  109:   // get the pointer
  110:   T* pointer(void);
  111:   const T* pointer(void) const;
  112: 
  113:   //////////////////////////////////////////////////////////////////////////////
  114:   // functions to manage counted referencing
  115: 
  116:   // test whether two pointers point to the same object(known as aliasing the object)
  117:   // used in the form if(a.aliases(b))
  118:   bool aliases(const simple_ptr<T>&) const;
  119: 
  120:   // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
  121:   unsigned alias_count(void) const;
  122: 
  123:   // make this pointer unique with respect to any other references to the same object
  124:   // if this pointer is already unique, it does nothing - otherwise it copies the object
  125:   void make_unique(void);
  126: 
  127:   // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
  128:   void clear(void);
  129: 
  130:   // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
  131:   void clear_unique(void);
  132: 
  133:   // make this pointer a unique copy of the parameter
  134:   // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
  135:   void copy(const simple_ptr<T>&);
  136:   // alternate form used in assignments: p1 = ps.copy()
  137:   simple_ptr<T> copy(void) const;
  138: 
  139:   // persistence functions
  140:   void dump(dump_context& str) const throw(persistent_dump_failed);
  141:   void restore(restore_context& str) throw(persistent_restore_failed);
  142: 
  143: protected:
  144:   T* m_pointer;
  145:   unsigned* m_count;
  146: };
  147: 
  148: ////////////////////////////////////////////////////////////////////////////////
  149: // comparisons required for using this class in an STL container
  150: // These require == and < operator in the contained type T
  151: // the remaining relational operators are provided by template functions
  152: // a null pointer is less-than a non-null, two nulls are equal
  153: // these funcions are defined as non-members so that you only need provide
  154: // the underlying T::operator< and == if you are going to use these functions
  155: 
  156: template<typename T>
  157: bool operator==(const simple_ptr<T>&, const simple_ptr<T>&);
  158: 
  159: template<typename T>
  160: bool operator<(const simple_ptr<T>&, const simple_ptr<T>&);
  161: 
  162: ////////////////////////////////////////////////////////////////////////////////
  163: // string/print utilities
  164: 
  165: template<typename T>
  166: std::string simple_ptr_to_string(const simple_ptr<T>& ptr, std::string null_string);
  167: 
  168: template<typename T>
  169: otext& print_simple_ptr(otext& str, const simple_ptr<T>& ptr, std::string null_string);
  170: 
  171: template<typename T>
  172: otext& print_simple_ptr(otext& str, const simple_ptr<T>& ptr, unsigned indent, std::string null_string);
  173: 
  174: ////////////////////////////////////////////////////////////////////////////////
  175: // persistence - call these rather than the methods
  176: // the dump routine dumps simple_ptr-specific information and then calls dump_pointer on the contents
  177: // similarly the restore routine calls restore_pointer
  178: // so therefore the class T should have non-member dump/restore functions
  179: 
  180: template<typename T>
  181: void dump_simple_ptr(dump_context& str, const simple_ptr<T>& data) throw(persistent_dump_failed);
  182: 
  183: template<typename T>
  184: void restore_simple_ptr(restore_context& str, simple_ptr<T>& data) throw(persistent_restore_failed);
  185: 
  186: ////////////////////////////////////////////////////////////////////////////////
  187: ////////////////////////////////////////////////////////////////////////////////
  188: // Cloning simple pointer class for polymorphic class hierarchies
  189: // The contained class T should implement the clonable interface defined in clonable.hpp
  190: ////////////////////////////////////////////////////////////////////////////////
  191: ////////////////////////////////////////////////////////////////////////////////
  192: 
  193: template<typename T>
  194: class simple_ptr_clone
  195: {
  196: public:
  197:   //////////////////////////////////////////////////////////////////////////////
  198:   // member type definitions
  199: 
  200:   typedef T value_type;
  201:   typedef T& reference;
  202:   typedef const T& const_reference;
  203: 
  204:   //////////////////////////////////////////////////////////////////////////////
  205:   // constructors, assignments and destructors
  206: 
  207:   // create a null pointer
  208:   simple_ptr_clone(void);
  209: 
  210:   // create a pointer containing a *copy* of the object
  211:   // this copy is taken because the pointer class maintains a dynamically allocated object 
  212:   // and the T& may not be (usually is not) dynamically allocated
  213:   // constructor form
  214:   simple_ptr_clone(const T& data);
  215:   // assignment form for an already-constructed smart-pointer
  216:   simple_ptr_clone<T>& operator=(const T& data);
  217: 
  218:   // copy constructor implements counted referencing - no copy is made
  219:   simple_ptr_clone(const simple_ptr_clone<T>& r);
  220:   // assignment of smart pointers implement counted referencing - no copy is made
  221:   simple_ptr_clone<T>& operator=(const simple_ptr_clone<T>&);
  222: 
  223:   // create a pointer containing a dynamically created object
  224:   // Note: the object must be allocated *by the user* with new
  225:   // constructor form - must be called in the form simple_ptr_clone<type> x(new type(args))
  226:   explicit simple_ptr_clone(T* data);
  227:   // assignment form
  228:   simple_ptr_clone<T>& operator= (T* data);
  229: 
  230:   // destructor decrements the reference count and delete only when the last reference is destroyed
  231:   ~simple_ptr_clone(void);
  232: 
  233:   //////////////////////////////////////////////////////////////////////////////
  234:   // logical tests to see if there is anything contained in the pointer since it can be null
  235: 
  236:   // there are two forms:explicit and implicit
  237:   // implicit: if(!r) or if(r)
  238:   // explicit: if(r.null()) or if(r.present())
  239:   operator bool(void) const;
  240:   bool operator!(void) const;
  241:   bool present(void) const;
  242:   bool null(void) const;
  243: 
  244:   //////////////////////////////////////////////////////////////////////////////
  245:   // dereference operators and functions
  246: 
  247:   // dereference the smart pointer to get the object - use in the form *p1
  248:   T& operator*(void) throw(null_dereference);
  249:   const T& operator*(void) const throw(null_dereference);
  250: 
  251:   // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
  252:   T* operator->(void) throw(null_dereference);
  253:   const T* operator->(void) const throw(null_dereference);
  254: 
  255:   //////////////////////////////////////////////////////////////////////////////
  256:   // explicit function forms of the above assignment and dereference operators
  257: 
  258:   // set the value
  259:   void set_value(const T& data);
  260:   // get the value
  261:   T& value(void) throw(null_dereference);
  262:   const T& value(void) const throw(null_dereference);
  263: 
  264:   // set the pointer
  265:   // deletes the previous pointer and adopts the passed pointer instead
  266:   // Note: the object must be allocated *by the user* with new
  267:   // Warning: it is very easy to break the memory management with this operation
  268:   void set(T* data = 0);
  269:   // get the pointer
  270:   T* pointer(void);
  271:   const T* pointer(void) const;
  272: 
  273:   //////////////////////////////////////////////////////////////////////////////
  274:   // functions to manage counted referencing
  275: 
  276:   // test whether two pointers point to the same object(known as aliasing the object)
  277:   // used in the form if(a.aliases(b))
  278:   bool aliases(const simple_ptr_clone<T>&) const;
  279: 
  280:   // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
  281:   unsigned alias_count(void) const;
  282: 
  283:   // make this pointer unique with respect to any other references to the same object
  284:   // if this pointer is already unique, it does nothing - otherwise it copies the object
  285:   void make_unique(void);
  286: 
  287:   // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
  288:   void clear(void);
  289: 
  290:   // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
  291:   void clear_unique(void);
  292: 
  293:   // make this pointer a unique copy of the parameter
  294:   // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
  295:   void copy(const simple_ptr_clone<T>&);
  296:   // alternate form used in assignments: p1 = ps.copy()
  297:   simple_ptr_clone<T> copy(void) const;
  298: 
  299:   // persistence functions
  300:   void dump(dump_context& str) const throw(persistent_dump_failed);
  301:   void restore(restore_context& str) throw(persistent_restore_failed);
  302: 
  303: protected:
  304:   T* m_pointer;
  305:   unsigned* m_count;
  306: };
  307: 
  308: ////////////////////////////////////////////////////////////////////////////////
  309: // comparisons required for using this class in an STL container
  310: // These require == and < operator in the contained type T
  311: // the remaining relational operators are provided by template functions
  312: // a null pointer is less-than a non-null, two nulls are equal
  313: // these funcions are defined as non-members so that you only need provide
  314: // the underlying T::operator< and == if you are going to use these functions
  315: 
  316: template<typename T>
  317: bool operator==(const simple_ptr_clone<T>&, const simple_ptr_clone<T>&);
  318: 
  319: template<typename T>
  320: bool operator<(const simple_ptr_clone<T>&, const simple_ptr_clone<T>&);
  321: 
  322: ////////////////////////////////////////////////////////////////////////////////
  323: // string/print utilities
  324: 
  325: template<typename T>
  326: std::string simple_ptr_clone_to_string(const simple_ptr_clone<T>& ptr, std::string null_string);
  327: 
  328: template<typename T>
  329: otext& print_simple_ptr_clone(otext& str, const simple_ptr_clone<T>& ptr, std::string null_string);
  330: 
  331: template<typename T>
  332: otext& print_simple_ptr_clone(otext& str, const simple_ptr_clone<T>& ptr, unsigned indent, std::string null_string);
  333: 
  334: ////////////////////////////////////////////////////////////////////////////////
  335: // persistence - call these rather than the methods
  336: // the dump routine dumps simple_ptr_clone-specific information and then calls dump_interface
  337: // similarly the restore routine calls restore_interface
  338: // so therefore the class T should implement the persistent interface defined by the class persistent in persistent.hpp
  339: 
  340: template<typename T>
  341: void dump_simple_ptr_clone(dump_context& str, const simple_ptr_clone<T>& data) throw(persistent_dump_failed);
  342: 
  343: template<typename T>
  344: void restore_simple_ptr_clone(restore_context& str, simple_ptr_clone<T>& data) throw(persistent_restore_failed);
  345: 
  346: ////////////////////////////////////////////////////////////////////////////////
  347: ////////////////////////////////////////////////////////////////////////////////
  348: // No-copy simple pointer class for managing objects that cannot be copied
  349: ////////////////////////////////////////////////////////////////////////////////
  350: ////////////////////////////////////////////////////////////////////////////////
  351: 
  352: template<typename T>
  353: class simple_ptr_nocopy
  354: {
  355: public:
  356:   //////////////////////////////////////////////////////////////////////////////
  357:   // member type definitions
  358: 
  359:   typedef T value_type;
  360:   typedef T& reference;
  361:   typedef const T& const_reference;
  362: 
  363:   //////////////////////////////////////////////////////////////////////////////
  364:   // constructors, assignments and destructors
  365: 
  366:   // create a null pointer
  367:   simple_ptr_nocopy(void);
  368: 
  369:   // copy constructor implements counted referencing - no copy is made
  370:   simple_ptr_nocopy(const simple_ptr_nocopy<T>& r);
  371:   // assignment of smart pointers implement counted referencing - no copy is made
  372:   simple_ptr_nocopy<T>& operator=(const simple_ptr_nocopy<T>&);
  373: 
  374:   // create a pointer containing a dynamically created object
  375:   // Note: the object must be allocated *by the user* with new
  376:   // constructor form - must be called in the form simple_ptr_nocopy<type> x(new type(args))
  377:   explicit simple_ptr_nocopy(T* data);
  378:   // assignment form
  379:   simple_ptr_nocopy<T>& operator= (T* data);
  380: 
  381:   // destructor decrements the reference count and delete only when the last reference is destroyed
  382:   ~simple_ptr_nocopy(void);
  383: 
  384:   //////////////////////////////////////////////////////////////////////////////
  385:   // logical tests to see if there is anything contained in the pointer since it can be null
  386: 
  387:   // there are two forms:explicit and implicit
  388:   // implicit: if(!r) or if(r)
  389:   // explicit: if(r.null()) or if(r.present())
  390:   operator bool(void) const;
  391:   bool operator!(void) const;
  392:   bool present(void) const;
  393:   bool null(void) const;
  394: 
  395:   //////////////////////////////////////////////////////////////////////////////
  396:   // dereference operators and functions
  397: 
  398:   // dereference the smart pointer to get the object - use in the form *p1
  399:   T& operator*(void) throw(null_dereference);
  400:   const T& operator*(void) const throw(null_dereference);
  401: 
  402:   // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
  403:   T* operator->(void) throw(null_dereference);
  404:   const T* operator->(void) const throw(null_dereference);
  405: 
  406:   //////////////////////////////////////////////////////////////////////////////
  407:   // explicit function forms of the above assignment and dereference operators
  408: 
  409:   // get the value
  410:   T& value(void) throw(null_dereference);
  411:   const T& value(void) const throw(null_dereference);
  412: 
  413:   // set the pointer
  414:   // deletes the previous pointer and adopts the passed pointer instead
  415:   // Note: the object must be allocated *by the user* with new
  416:   // Warning: it is very easy to break the memory management with this operation
  417:   void set(T* data = 0);
  418:   // get the pointer
  419:   T* pointer(void);
  420:   const T* pointer(void) const;
  421: 
  422:   //////////////////////////////////////////////////////////////////////////////
  423:   // functions to manage counted referencing
  424: 
  425:   // test whether two pointers point to the same object(known as aliasing the object)
  426:   // used in the form if(a.aliases(b))
  427:   bool aliases(const simple_ptr_nocopy<T>&) const;
  428: 
  429:   // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
  430:   unsigned alias_count(void) const;
  431: 
  432:   // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
  433:   void clear(void);
  434: 
  435:   // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
  436:   void clear_unique(void);
  437: 
  438: protected:
  439:   T* m_pointer;
  440:   unsigned* m_count;
  441: };
  442: 
  443: ////////////////////////////////////////////////////////////////////////////////
  444: // comparisons required for using this class in an STL container
  445: // These require == and < operator in the contained type T
  446: // the remaining relational operators are provided by template functions
  447: // a null pointer is less-than a non-null, two nulls are equal
  448: // these funcions are defined as non-members so that you only need provide
  449: // the underlying T::operator< and == if you are going to use these functions
  450: 
  451: template<typename T>
  452: bool operator==(const simple_ptr_nocopy<T>&, const simple_ptr_nocopy<T>&);
  453: 
  454: template<typename T>
  455: bool operator<(const simple_ptr_nocopy<T>&, const simple_ptr_nocopy<T>&);
  456: 
  457: ////////////////////////////////////////////////////////////////////////////////
  458: // string/print utilities
  459: 
  460: template<typename T>
  461: std::string simple_ptr_nocopy_to_string(const simple_ptr_nocopy<T>& ptr, std::string null_string);
  462: 
  463: template<typename T>
  464: otext& print_simple_ptr_nocopy(otext& str, const simple_ptr_nocopy<T>& ptr, std::string null_string);
  465: 
  466: template<typename T>
  467: otext& print_simple_ptr_nocopy(otext& str, const simple_ptr_nocopy<T>& ptr, unsigned indent, std::string null_string);
  468: 
  469: ////////////////////////////////////////////////////////////////////////////////
  470: // there's no persistence on simple_ptr_nocopy because the whole point is that
  471: // it stores an uncopyable object and persistence is a form of copying
  472: 
  473: ////////////////////////////////////////////////////////////////////////////////
  474: ////////////////////////////////////////////////////////////////////////////////
  475: // Simple smart pointer class
  476: ////////////////////////////////////////////////////////////////////////////////
  477: ////////////////////////////////////////////////////////////////////////////////
  478: 
  479: ////////////////////////////////////////////////////////////////////////////////
  480: // internals
  481: 
  482: template<typename T> class smart_ptr_holder;
  483: 
  484: ////////////////////////////////////////////////////////////////////////////////
  485: 
  486: template<typename T>
  487: class smart_ptr
  488: {
  489: public:
  490:   //////////////////////////////////////////////////////////////////////////////
  491:   // member type definitions
  492: 
  493:   typedef T value_type;
  494:   typedef T& reference;
  495:   typedef const T& const_reference;
  496: 
  497:   //////////////////////////////////////////////////////////////////////////////
  498:   // constructors, assignments and destructors
  499: 
  500:   // create a null pointer
  501:   smart_ptr(void);
  502: 
  503:   // create a pointer containing a *copy* of the object
  504:   // this copy is taken because the pointer class maintains a dynamically allocated object 
  505:   // and the T& may not be (usually is not) dynamically allocated
  506:   // constructor form
  507:   smart_ptr(const T& data);
  508:   // assignment form for an already-constructed smart-pointer
  509:   smart_ptr<T>& operator=(const T& data);
  510: 
  511:   // copy constructor implements counted referencing - no copy is made
  512:   smart_ptr(const smart_ptr<T>& r);
  513:   // assignment of smart pointers implement counted referencing - no copy is made
  514:   smart_ptr<T>& operator=(const smart_ptr<T>&);
  515: 
  516:   // create a pointer containing a dynamically created object
  517:   // Note: the object must be allocated *by the user* with new
  518:   // constructor form - must be called in the form smart_ptr<type> x(new type(args))
  519:   explicit smart_ptr(T* data);
  520:   // assignment form
  521:   smart_ptr<T>& operator= (T* data);
  522: 
  523:   // destructor decrements the reference count and delete only when the last reference is destroyed
  524:   ~smart_ptr(void);
  525: 
  526:   //////////////////////////////////////////////////////////////////////////////
  527:   // logical tests to see if there is anything contained in the pointer since it can be null
  528: 
  529:   // there are two forms:explicit and implicit
  530:   // implicit: if(!r) or if(r)
  531:   // explicit: if(r.null()) or if(r.present())
  532:   operator bool(void) const;
  533:   bool operator!(void) const;
  534:   bool present(void) const;
  535:   bool null(void) const;
  536: 
  537:   //////////////////////////////////////////////////////////////////////////////
  538:   // dereference operators and functions
  539: 
  540:   // dereference the smart pointer to get the object - use in the form *p1
  541:   T& operator*(void) throw(null_dereference);
  542:   const T& operator*(void) const throw(null_dereference);
  543: 
  544:   // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
  545:   T* operator->(void) throw(null_dereference);
  546:   const T* operator->(void) const throw(null_dereference);
  547: 
  548:   //////////////////////////////////////////////////////////////////////////////
  549:   // explicit function forms of the above assignment and dereference operators
  550: 
  551:   // set the value
  552:   void set_value(const T& data);
  553:   // get the value
  554:   T& value(void) throw(null_dereference);
  555:   const T& value(void) const throw(null_dereference);
  556: 
  557:   // set the pointer
  558:   // deletes the previous pointer and adopts the passed pointer instead
  559:   // Note: the object must be allocated *by the user* with new
  560:   // Warning: it is very easy to break the memory management with this operation
  561:   void set(T* data = 0);
  562:   // get the pointer
  563:   T* pointer(void);
  564:   const T* pointer(void) const;
  565: 
  566:   //////////////////////////////////////////////////////////////////////////////
  567:   // functions to manage counted referencing
  568: 
  569:   // test whether two pointers point to the same object(known as aliasing the object)
  570:   // used in the form if(a.aliases(b))
  571:   bool aliases(const smart_ptr<T>&) const;
  572: 
  573:   // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
  574:   unsigned alias_count(void) const;
  575: 
  576:   // make this pointer unique with respect to any other references to the same object
  577:   // if this pointer is already unique, it does nothing - otherwise it copies the object
  578:   void make_unique(void);
  579: 
  580:   // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
  581:   void clear(void);
  582: 
  583:   // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
  584:   void clear_unique(void);
  585: 
  586:   // make this pointer a unique copy of the parameter
  587:   // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
  588:   void copy(const smart_ptr<T>&);
  589:   // alternate form used in assignments: p1 = ps.copy()
  590:   smart_ptr<T> copy(void) const;
  591: 
  592:   // persistence functions
  593:   void dump(dump_context& str) const throw(persistent_dump_failed);
  594:   void restore(restore_context& str) throw(persistent_restore_failed);
  595: 
  596: protected:
  597:   smart_ptr_holder<T>* m_holder;
  598: };
  599: 
  600: ////////////////////////////////////////////////////////////////////////////////
  601: // comparisons required for using this class in an STL container
  602: // These require == and < operator in the contained type T
  603: // the remaining relational operators are provided by template functions
  604: // a null pointer is less-than a non-null, two nulls are equal
  605: // these funcions are defined as non-members so that you only need provide
  606: // the underlying T::operator< and == if you are going to use these functions
  607: 
  608: template<typename T>
  609: bool operator==(const smart_ptr<T>&, const smart_ptr<T>&);
  610: 
  611: template<typename T>
  612: bool operator<(const smart_ptr<T>&, const smart_ptr<T>&);
  613: 
  614: ////////////////////////////////////////////////////////////////////////////////
  615: // string/print utilities
  616: 
  617: template<typename T>
  618: std::string smart_ptr_to_string(const smart_ptr<T>& ptr, std::string null_string);
  619: 
  620: template