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) Southampton University 1999-2004
7: (c) Andy Rushton 2004-2009
8: License: BSD License, see ../docs/license.html
9:
10: Dan Milton: three simple pointer containers with single level access:
11: - simple_ptr for simple types and classes
12: - simple_ptr_clone for polymorphic class hierarchies
13: - simple_ptr_nocopy for any class that cannot or should no be copied
14:
15: Andy Rushton: three smart pointer containers with two-layer access:
16: - smart_ptr for simple types and classes
17: - smart_ptr_clone for polymorphic class hierarchies
18: - smart_ptr_nocopy for any class that cannot or should no be copied
19:
20: ------------------------------------------------------------------------------*/
21: #include "os_fixes.hpp"
22: #include "exceptions.hpp"
23: #include "persistent.hpp"
24: #include "textio.hpp"
25: #include <map>
26: #include <string>
27:
28: ////////////////////////////////////////////////////////////////////////////////
29: ////////////////////////////////////////////////////////////////////////////////
30: // Simple pointer class
31: ////////////////////////////////////////////////////////////////////////////////
32: ////////////////////////////////////////////////////////////////////////////////
33:
34: template<typename T>
35: class simple_ptr
36: {
37: public:
38: //////////////////////////////////////////////////////////////////////////////
39: // member type definitions
40:
41: typedef T value_type;
42: typedef T& reference;
43: typedef const T& const_reference;
44:
45: //////////////////////////////////////////////////////////////////////////////
46: // constructors, assignments and destructors
47:
48: // create a null pointer
49: simple_ptr(void);
50:
51: // create a pointer containing a *copy* of the object
52: // this copy is taken because the pointer class maintains a dynamically allocated object
53: // and the T& may not be (usually is not) dynamically allocated
54: // constructor form
55: simple_ptr(const T& data);
56: // assignment form for an already-constructed smart-pointer
57: simple_ptr<T>& operator=(const T& data);
58:
59: // copy constructor implements counted referencing - no copy is made
60: simple_ptr(const simple_ptr<T>& r);
61: // assignment of smart pointers implement counted referencing - no copy is made
62: simple_ptr<T>& operator=(const simple_ptr<T>&);
63:
64: // create a pointer containing a dynamically created object
65: // Note: the object must be allocated *by the user* with new
66: // constructor form - must be called in the form simple_ptr<type> x(new type(args))
67: explicit simple_ptr(T* data);
68: // assignment form
69: simple_ptr<T>& operator= (T* data);
70:
71: // destructor decrements the reference count and delete only when the last reference is destroyed
72: ~simple_ptr(void);
73:
74: //////////////////////////////////////////////////////////////////////////////
75: // logical tests to see if there is anything contained in the pointer since it can be null
76:
77: // there are two forms:explicit and implicit
78: // implicit: if(!r) or if(r)
79: // explicit: if(r.null()) or if(r.present())
80: operator bool(void) const;
81: bool operator!(void) const;
82: bool present(void) const;
83: bool null(void) const;
84:
85: //////////////////////////////////////////////////////////////////////////////
86: // dereference operators and functions
87:
88: // dereference the smart pointer to get the object - use in the form *p1
89: T& operator*(void) throw(null_dereference);
90: const T& operator*(void) const throw(null_dereference);
91:
92: // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
93: T* operator->(void) throw(null_dereference);
94: const T* operator->(void) const throw(null_dereference);
95:
96: //////////////////////////////////////////////////////////////////////////////
97: // explicit function forms of the above assignment and dereference operators
98:
99: // set the value
100: void set_value(const T& data);
101: // get the value
102: T& value(void) throw(null_dereference);
103: const T& value(void) const throw(null_dereference);
104:
105: // set the pointer
106: // deletes the previous pointer and adopts the passed pointer instead
107: // Note: the object must be allocated *by the user* with new
108: // Warning: it is very easy to break the memory management with this operation
109: void set(T* data = 0);
110: // get the pointer
111: T* pointer(void);
112: const T* pointer(void) const;
113:
114: //////////////////////////////////////////////////////////////////////////////
115: // functions to manage counted referencing
116:
117: // test whether two pointers point to the same object(known as aliasing the object)
118: // used in the form if(a.aliases(b))
119: bool aliases(const simple_ptr<T>&) const;
120:
121: // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
122: unsigned alias_count(void) const;
123:
124: // make this pointer unique with respect to any other references to the same object
125: // if this pointer is already unique, it does nothing - otherwise it copies the object
126: void make_unique(void);
127:
128: // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
129: void clear(void);
130:
131: // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
132: void clear_unique(void);
133:
134: // make this pointer a unique copy of the parameter
135: // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
136: void copy(const simple_ptr<T>&);
137: // alternate form used in assignments: p1 = ps.copy()
138: simple_ptr<T> copy(void) const;
139:
140: // persistence functions
141: void dump(dump_context& str) const throw(persistent_dump_failed);
142: void restore(restore_context& str) throw(persistent_restore_failed);
143:
144: protected:
145: T* m_pointer;
146: unsigned* m_count;
147: };
148:
149: ////////////////////////////////////////////////////////////////////////////////
150: // comparisons required for using this class in an STL container
151: // These require == and < operator in the contained type T
152: // the remaining relational operators are provided by template functions
153: // a null pointer is less-than a non-null, two nulls are equal
154: // these funcions are defined as non-members so that you only need provide
155: // the underlying T::operator< and == if you are going to use these functions
156:
157: template<typename T>
158: bool operator==(const simple_ptr<T>&, const simple_ptr<T>&);
159:
160: template<typename T>
161: bool operator<(const simple_ptr<T>&, const simple_ptr<T>&);
162:
163: ////////////////////////////////////////////////////////////////////////////////
164: // string/print utilities
165:
166: template<typename T>
167: std::string simple_ptr_to_string(const simple_ptr<T>& ptr, std::string null_string);
168:
169: template<typename T>
170: otext& print_simple_ptr(otext& str, const simple_ptr<T>& ptr, std::string null_string);
171:
172: template<typename T>
173: otext& print_simple_ptr(otext& str, const simple_ptr<T>& ptr, unsigned indent, std::string null_string);
174:
175: ////////////////////////////////////////////////////////////////////////////////
176: // persistence - call these rather than the methods
177: // the dump routine dumps simple_ptr-specific information and then calls dump_pointer on the contents
178: // similarly the restore routine calls restore_pointer
179: // so therefore the class T should have non-member dump/restore functions
180:
181: template<typename T>
182: void dump_simple_ptr(dump_context& str, const simple_ptr<T>& data) throw(persistent_dump_failed);
183:
184: template<typename T>
185: void restore_simple_ptr(restore_context& str, simple_ptr<T>& data) throw(persistent_restore_failed);
186:
187: ////////////////////////////////////////////////////////////////////////////////
188: ////////////////////////////////////////////////////////////////////////////////
189: // Cloning simple pointer class for polymorphic class hierarchies
190: // The contained class T should implement the clonable interface defined in clonable.hpp
191: ////////////////////////////////////////////////////////////////////////////////
192: ////////////////////////////////////////////////////////////////////////////////
193:
194: template<typename T>
195: class simple_ptr_clone
196: {
197: public:
198: //////////////////////////////////////////////////////////////////////////////
199: // member type definitions
200:
201: typedef T value_type;
202: typedef T& reference;
203: typedef const T& const_reference;
204:
205: //////////////////////////////////////////////////////////////////////////////
206: // constructors, assignments and destructors
207:
208: // create a null pointer
209: simple_ptr_clone(void);
210:
211: // create a pointer containing a *copy* of the object
212: // this copy is taken because the pointer class maintains a dynamically allocated object
213: // and the T& may not be (usually is not) dynamically allocated
214: // constructor form
215: simple_ptr_clone(const T& data);
216: // assignment form for an already-constructed smart-pointer
217: simple_ptr_clone<T>& operator=(const T& data);
218:
219: // copy constructor implements counted referencing - no copy is made
220: simple_ptr_clone(const simple_ptr_clone<T>& r);
221: // assignment of smart pointers implement counted referencing - no copy is made
222: simple_ptr_clone<T>& operator=(const simple_ptr_clone<T>&);
223:
224: // create a pointer containing a dynamically created object
225: // Note: the object must be allocated *by the user* with new
226: // constructor form - must be called in the form simple_ptr_clone<type> x(new type(args))
227: explicit simple_ptr_clone(T* data);
228: // assignment form
229: simple_ptr_clone<T>& operator= (T* data);
230:
231: // destructor decrements the reference count and delete only when the last reference is destroyed
232: ~simple_ptr_clone(void);
233:
234: //////////////////////////////////////////////////////////////////////////////
235: // logical tests to see if there is anything contained in the pointer since it can be null
236:
237: // there are two forms:explicit and implicit
238: // implicit: if(!r) or if(r)
239: // explicit: if(r.null()) or if(r.present())
240: operator bool(void) const;
241: bool operator!(void) const;
242: bool present(void) const;
243: bool null(void) const;
244:
245: //////////////////////////////////////////////////////////////////////////////
246: // dereference operators and functions
247:
248: // dereference the smart pointer to get the object - use in the form *p1
249: T& operator*(void) throw(null_dereference);
250: const T& operator*(void) const throw(null_dereference);
251:
252: // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
253: T* operator->(void) throw(null_dereference);
254: const T* operator->(void) const throw(null_dereference);
255:
256: //////////////////////////////////////////////////////////////////////////////
257: // explicit function forms of the above assignment and dereference operators
258:
259: // set the value
260: void set_value(const T& data);
261: // get the value
262: T& value(void) throw(null_dereference);
263: const T& value(void) const throw(null_dereference);
264:
265: // set the pointer
266: // deletes the previous pointer and adopts the passed pointer instead
267: // Note: the object must be allocated *by the user* with new
268: // Warning: it is very easy to break the memory management with this operation
269: void set(T* data = 0);
270: // get the pointer
271: T* pointer(void);
272: const T* pointer(void) const;
273:
274: //////////////////////////////////////////////////////////////////////////////
275: // functions to manage counted referencing
276:
277: // test whether two pointers point to the same object(known as aliasing the object)
278: // used in the form if(a.aliases(b))
279: bool aliases(const simple_ptr_clone<T>&) const;
280:
281: // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
282: unsigned alias_count(void) const;
283:
284: // make this pointer unique with respect to any other references to the same object
285: // if this pointer is already unique, it does nothing - otherwise it copies the object
286: void make_unique(void);
287:
288: // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
289: void clear(void);
290:
291: // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
292: void clear_unique(void);
293:
294: // make this pointer a unique copy of the parameter
295: // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
296: void copy(const simple_ptr_clone<T>&);
297: // alternate form used in assignments: p1 = ps.copy()
298: simple_ptr_clone<T> copy(void) const;
299:
300: // persistence functions
301: void dump(dump_context& str) const throw(persistent_dump_failed);
302: void restore(restore_context& str) throw(persistent_restore_failed);
303:
304: protected:
305: T* m_pointer;
306: unsigned* m_count;
307: };
308:
309: ////////////////////////////////////////////////////////////////////////////////
310: // comparisons required for using this class in an STL container
311: // These require == and < operator in the contained type T
312: // the remaining relational operators are provided by template functions
313: // a null pointer is less-than a non-null, two nulls are equal
314: // these funcions are defined as non-members so that you only need provide
315: // the underlying T::operator< and == if you are going to use these functions
316:
317: template<typename T>
318: bool operator==(const simple_ptr_clone<T>&, const simple_ptr_clone<T>&);
319:
320: template<typename T>
321: bool operator<(const simple_ptr_clone<T>&, const simple_ptr_clone<T>&);
322:
323: ////////////////////////////////////////////////////////////////////////////////
324: // string/print utilities
325:
326: template<typename T>
327: std::string simple_ptr_clone_to_string(const simple_ptr_clone<T>& ptr, std::string null_string);
328:
329: template<typename T>
330: otext& print_simple_ptr_clone(otext& str, const simple_ptr_clone<T>& ptr, std::string null_string);
331:
332: template<typename T>
333: otext& print_simple_ptr_clone(otext& str, const simple_ptr_clone<T>& ptr, unsigned indent, std::string null_string);
334:
335: ////////////////////////////////////////////////////////////////////////////////
336: // persistence - call these rather than the methods
337: // the dump routine dumps simple_ptr_clone-specific information and then calls dump_interface
338: // similarly the restore routine calls restore_interface
339: // so therefore the class T should implement the persistent interface defined by the class persistent in persistent.hpp
340:
341: template<typename T>
342: void dump_simple_ptr_clone(dump_context& str, const simple_ptr_clone<T>& data) throw(persistent_dump_failed);
343:
344: template<typename T>
345: void restore_simple_ptr_clone(restore_context& str, simple_ptr_clone<T>& data) throw(persistent_restore_failed);
346:
347: ////////////////////////////////////////////////////////////////////////////////
348: ////////////////////////////////////////////////////////////////////////////////
349: // No-copy simple pointer class for managing objects that cannot be copied
350: ////////////////////////////////////////////////////////////////////////////////
351: ////////////////////////////////////////////////////////////////////////////////
352:
353: template<typename T>
354: class simple_ptr_nocopy
355: {
356: public:
357: //////////////////////////////////////////////////////////////////////////////
358: // member type definitions
359:
360: typedef T value_type;
361: typedef T& reference;
362: typedef const T& const_reference;
363:
364: //////////////////////////////////////////////////////////////////////////////
365: // constructors, assignments and destructors
366:
367: // create a null pointer
368: simple_ptr_nocopy(void);
369:
370: // copy constructor implements counted referencing - no copy is made
371: simple_ptr_nocopy(const simple_ptr_nocopy<T>& r);
372: // assignment of smart pointers implement counted referencing - no copy is made
373: simple_ptr_nocopy<T>& operator=(const simple_ptr_nocopy<T>&);
374:
375: // create a pointer containing a dynamically created object
376: // Note: the object must be allocated *by the user* with new
377: // constructor form - must be called in the form simple_ptr_nocopy<type> x(new type(args))
378: explicit simple_ptr_nocopy(T* data);
379: // assignment form
380: simple_ptr_nocopy<T>& operator= (T* data);
381:
382: // destructor decrements the reference count and delete only when the last reference is destroyed
383: ~simple_ptr_nocopy(void);
384:
385: //////////////////////////////////////////////////////////////////////////////
386: // logical tests to see if there is anything contained in the pointer since it can be null
387:
388: // there are two forms:explicit and implicit
389: // implicit: if(!r) or if(r)
390: // explicit: if(r.null()) or if(r.present())
391: operator bool(void) const;
392: bool operator!(void) const;
393: bool present(void) const;
394: bool null(void) const;
395:
396: //////////////////////////////////////////////////////////////////////////////
397: // dereference operators and functions
398:
399: // dereference the smart pointer to get the object - use in the form *p1
400: T& operator*(void) throw(null_dereference);
401: const T& operator*(void) const throw(null_dereference);
402:
403: // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
404: T* operator->(void) throw(null_dereference);
405: const T* operator->(void) const throw(null_dereference);
406:
407: //////////////////////////////////////////////////////////////////////////////
408: // explicit function forms of the above assignment and dereference operators
409:
410: // get the value
411: T& value(void) throw(null_dereference);
412: const T& value(void) const throw(null_dereference);
413:
414: // set the pointer
415: // deletes the previous pointer and adopts the passed pointer instead
416: // Note: the object must be allocated *by the user* with new
417: // Warning: it is very easy to break the memory management with this operation
418: void set(T* data = 0);
419: // get the pointer
420: T* pointer(void);
421: const T* pointer(void) const;
422:
423: //////////////////////////////////////////////////////////////////////////////
424: // functions to manage counted referencing
425:
426: // test whether two pointers point to the same object(known as aliasing the object)
427: // used in the form if(a.aliases(b))
428: bool aliases(const simple_ptr_nocopy<T>&) const;
429:
430: // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
431: unsigned alias_count(void) const;
432:
433: // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
434: void clear(void);
435:
436: // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
437: void clear_unique(void);
438:
439: protected:
440: T* m_pointer;
441: unsigned* m_count;
442: };
443:
444: ////////////////////////////////////////////////////////////////////////////////
445: // comparisons required for using this class in an STL container
446: // These require == and < operator in the contained type T
447: // the remaining relational operators are provided by template functions
448: // a null pointer is less-than a non-null, two nulls are equal
449: // these funcions are defined as non-members so that you only need provide
450: // the underlying T::operator< and == if you are going to use these functions
451:
452: template<typename T>
453: bool operator==(const simple_ptr_nocopy<T>&, const simple_ptr_nocopy<T>&);
454:
455: template<typename T>
456: bool operator<(const simple_ptr_nocopy<T>&, const simple_ptr_nocopy<T>&);
457:
458: ////////////////////////////////////////////////////////////////////////////////
459: // string/print utilities
460:
461: template<typename T>
462: std::string simple_ptr_nocopy_to_string(const simple_ptr_nocopy<T>& ptr, std::string null_string);
463:
464: template<typename T>
465: otext& print_simple_ptr_nocopy(otext& str, const simple_ptr_nocopy<T>& ptr, std::string null_string);
466:
467: template<typename T>
468: otext& print_simple_ptr_nocopy(otext& str, const simple_ptr_nocopy<T>& ptr, unsigned indent, std::string null_string);
469:
470: ////////////////////////////////////////////////////////////////////////////////
471: // there's no persistence on simple_ptr_nocopy because the whole point is that
472: // it stores an uncopyable object and persistence is a form of copying
473:
474: ////////////////////////////////////////////////////////////////////////////////
475: ////////////////////////////////////////////////////////////////////////////////
476: // Simple smart pointer class
477: ////////////////////////////////////////////////////////////////////////////////
478: ////////////////////////////////////////////////////////////////////////////////
479:
480: ////////////////////////////////////////////////////////////////////////////////
481: // internals
482:
483: template<typename T> class smart_ptr_holder;
484:
485: ////////////////////////////////////////////////////////////////////////////////
486:
487: template<typename T>
488: class smart_ptr
489: {
490: public:
491: //////////////////////////////////////////////////////////////////////////////
492: // member type definitions
493:
494: typedef T value_type;
495: typedef T& reference;
496: typedef const T& const_reference;
497:
498: //////////////////////////////////////////////////////////////////////////////
499: // constructors, assignments and destructors
500:
501: // create a null pointer
502: smart_ptr(void);
503:
504: // create a pointer containing a *copy* of the object
505: // this copy is taken because the pointer class maintains a dynamically allocated object
506: // and the T& may not be (usually is not) dynamically allocated
507: // constructor form
508: smart_ptr(const T& data);
509: // assignment form for an already-constructed smart-pointer
510: smart_ptr<T>& operator=(const T& data);
511:
512: // copy constructor implements counted referencing - no copy is made
513: smart_ptr(const smart_ptr<T>& r);
514: // assignment of smart pointers implement counted referencing - no copy is made
515: smart_ptr<T>& operator=(const smart_ptr<T>&);
516:
517: // create a pointer containing a dynamically created object
518: // Note: the object must be allocated *by the user* with new
519: // constructor form - must be called in the form smart_ptr<type> x(new type(args))
520: explicit smart_ptr(T* data);
521: // assignment form
522: smart_ptr<T>& operator= (T* data);
523:
524: // destructor decrements the reference count and delete only when the last reference is destroyed
525: ~smart_ptr(void);
526:
527: //////////////////////////////////////////////////////////////////////////////
528: // logical tests to see if there is anything contained in the pointer since it can be null
529:
530: // there are two forms:explicit and implicit
531: // implicit: if(!r) or if(r)
532: // explicit: if(r.null()) or if(r.present())
533: operator bool(void) const;
534: bool operator!(void) const;
535: bool present(void) const;
536: bool null(void) const;
537:
538: //////////////////////////////////////////////////////////////////////////////
539: // dereference operators and functions
540:
541: // dereference the smart pointer to get the object - use in the form *p1
542: T& operator*(void) throw(null_dereference);
543: const T& operator*(void) const throw(null_dereference);
544:
545: // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
546: T* operator->(void) throw(null_dereference);
547: const T* operator->(void) const throw(null_dereference);
548:
549: //////////////////////////////////////////////////////////////////////////////
550: // explicit function forms of the above assignment and dereference operators
551:
552: // set the value
553: void set_value(const T& data);
554: // get the value
555: T& value(void) throw(null_dereference);
556: const T& value(void) const throw(null_dereference);
557:
558: // set the pointer
559: // deletes the previous pointer and adopts the passed pointer instead
560: // Note: the object must be allocated *by the user* with new
561: // Warning: it is very easy to break the memory management with this operation
562: void set(T* data = 0);
563: // get the pointer
564: T* pointer(void);
565: const T* pointer(void) const;
566:
567: //////////////////////////////////////////////////////////////////////////////
568: // functions to manage counted referencing
569:
570: // test whether two pointers point to the same object(known as aliasing the object)
571: // used in the form if(a.aliases(b))
572: bool aliases(const smart_ptr<T>&) const;
573:
574: // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
575: unsigned alias_count(void) const;
576:
577: // make this pointer unique with respect to any other references to the same object
578: // if this pointer is already unique, it does nothing - otherwise it copies the object
579: void make_unique(void);
580:
581: // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
582: void clear(void);
583:
584: // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
585: void clear_unique(void);
586:
587: // make this pointer a unique copy of the parameter
588: // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
589: void copy(const smart_ptr<T>&);
590: // alternate form used in assignments: p1 = ps.copy()
591: smart_ptr<T> copy(void) const;
592:
593: // persistence functions
594: void dump(dump_context& str) const throw(persistent_dump_failed);
595: void restore(restore_context& str) throw(persistent_restore_failed);
596:
597: protected:
598: smart_ptr_holder<T>* m_holder;
599: };
600:
601: ////////////////////////////////////////////////////////////////////////////////
602: // comparisons required for using this class in an STL container
603: // These require == and < operator in the contained type T
604: // the remaining relational operators are provided by template functions
605: // a null pointer is less-than a non-null, two nulls are equal
606: // these funcions are defined as non-members so that you only need provide
607: // the underlying T::operator< and == if you are going to use these functions
608:
609: template<typename T>
610: bool operator==(const smart_ptr<T>&, const smart_ptr<T>&);
611:
612: template<typename T>
613: bool operator<(const smart_ptr<T>&, const smart_ptr<T>&);
614:
615: ////////////////////////////////////////////////////////////////////////////////
616: // string/print utilities
617:
618: template<typename T>
619: std::string smart_ptr_to_string(const smart_ptr<T>& ptr, std::string null_string);
620:
621: template<typename T>
622: otext& print_smart_ptr(otext& str, const smart_ptr<T>& ptr, std::string null_string);
623:
624: template<typename T>
625: otext& print_smart_ptr(otext& str, const smart_ptr<T>& ptr, unsigned indent, std::string null_string);
626:
627: ////////////////////////////////////////////////////////////////////////////////
628: // persistence - call these rather than the methods
629: // the dump routine dumps smart_ptr-specific information and then calls dump_pointer on the contents
630: // similarly the restore routine calls restore_pointer
631: // so therefore the class T should have non-member dump/restore functions
632:
633: template<typename T>
634: void dump_smart_ptr(dump_context& str, const smart_ptr<T>& data) throw(persistent_dump_failed);
635:
636: template<typename T>
637: void restore_smart_ptr(restore_context& str, smart_ptr<T>& data) throw(persistent_restore_failed);
638:
639: ////////////////////////////////////////////////////////////////////////////////
640: ////////////////////////////////////////////////////////////////////////////////
641: // Cloning smart pointer class for polymorphic class hierarchies
642: // The contained class T should implement the clonable interface defined in clonable.hpp
643: ////////////////////////////////////////////////////////////////////////////////
644: ////////////////////////////////////////////////////////////////////////////////
645:
646: template<typename T>
647: class smart_ptr_clone
648: {
649: public:
650: //////////////////////////////////////////////////////////////////////////////
651: // member type definitions
652:
653: typedef T value_type;
654: typedef T& reference;
655: typedef const T& const_reference;
656:
657: //////////////////////////////////////////////////////////////////////////////
658: // constructors, assignments and destructors
659:
660: // create a null pointer
661: smart_ptr_clone(void);
662:
663: // create a pointer containing a *copy* of the object
664: // this copy is taken because the pointer class maintains a dynamically allocated object
665: // and the T& may not be (usually is not) dynamically allocated
666: // constructor form
667: smart_ptr_clone(const T& data);
668: // assignment form for an already-constructed smart-pointer
669: smart_ptr_clone<T>& operator=(const T& data);
670:
671: // copy constructor implements counted referencing - no copy is made
672: smart_ptr_clone(const smart_ptr_clone<T>& r);
673: // assignment of smart pointers implement counted referencing - no copy is made
674: smart_ptr_clone<T>& operator=(const smart_ptr_clone<T>&);
675:
676: // create a pointer containing a dynamically created object
677: // Note: the object must be allocated *by the user* with new
678: // constructor form - must be called in the form smart_ptr_clone<type> x(new type(args))
679: explicit smart_ptr_clone(T* data);
680: // assignment form
681: smart_ptr_clone<T>& operator= (T* data);
682:
683: // destructor decrements the reference count and delete only when the last reference is destroyed
684: ~smart_ptr_clone(void);
685:
686: //////////////////////////////////////////////////////////////////////////////
687: // logical tests to see if there is anything contained in the pointer since it can be null
688:
689: // there are two forms:explicit and implicit
690: // implicit: if(!r) or if(r)
691: // explicit: if(r.null()) or if(r.present())
692: operator bool(void) const;
693: bool operator!(void) const;
694: bool present(void) const;
695: bool null(void) const;
696:
697: //////////////////////////////////////////////////////////////////////////////
698: // dereference operators and functions
699:
700: // dereference the smart pointer to get the object - use in the form *p1
701: T& operator*(void) throw(null_dereference);
702: const T& operator*(void) const throw(null_dereference);
703:
704: // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
705: T* operator->(void) throw(null_dereference);
706: const T* operator->(void) const throw(null_dereference);
707:
708: //////////////////////////////////////////////////////////////////////////////
709: // explicit function forms of the above assignment and dereference operators
710:
711: // set the value
712: void set_value(const T& data);
713: // get the value
714: T& value(void) throw(null_dereference);
715: const T& value(void) const throw(null_dereference);
716:
717: // set the pointer
718: // deletes the previous pointer and adopts the passed pointer instead
719: // Note: the object must be allocated *by the user* with new
720: // Warning: it is very easy to break the memory management with this operation
721: void set(T* data = 0);
722: // get the pointer
723: T* pointer(void);
724: const T* pointer(void) const;
725:
726: //////////////////////////////////////////////////////////////////////////////
727: // functions to manage counted referencing
728:
729: // test whether two pointers point to the same object(known as aliasing the object)
730: // used in the form if(a.aliases(b))
731: bool aliases(const smart_ptr_clone<T>&) const;
732:
733: // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
734: unsigned alias_count(void) const;
735:
736: // make this pointer unique with respect to any other references to the same object
737: // if this pointer is already unique, it does nothing - otherwise it copies the object
738: void make_unique(void);
739:
740: // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
741: void clear(void);
742:
743: // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
744: void clear_unique(void);
745:
746: // make this pointer a unique copy of the parameter
747: // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
748: void copy(const smart_ptr_clone<T>&);
749: // alternate form used in assignments: p1 = ps.copy()
750: smart_ptr_clone<T> copy(void) const;
751:
752: // persistence functions
753: void dump(dump_context& str) const throw(persistent_dump_failed);
754: void restore(restore_context& str) throw(persistent_restore_failed);
755:
756: protected:
757: smart_ptr_holder<T>* m_holder;
758: };
759:
760: ////////////////////////////////////////////////////////////////////////////////
761: // comparisons required for using this class in an STL container
762: // These require == and < operator in the contained type T
763: // the remaining relational operators are provided by template functions
764: // a null pointer is less-than a non-null, two nulls are equal
765: // these funcions are defined as non-members so that you only need provide
766: // the underlying T::operator< and == if you are going to use these functions
767:
768: template<typename T>
769: bool operator==(const smart_ptr_clone<T>&, const smart_ptr_clone<T>&);
770:
771: template<typename T>
772: bool operator<(const smart_ptr_clone<T>&, const smart_ptr_clone<T>&);
773:
774: ////////////////////////////////////////////////////////////////////////////////
775: // string/print utilities
776:
777: template<typename T>
778: std::string smart_ptr_clone_to_string(const smart_ptr_clone<T>& ptr, std::string null_string);
779:
780: template<typename T>
781: otext& print_smart_ptr_clone(otext& str, const smart_ptr_clone<T>& ptr, std::string null_string);
782:
783: template<typename T>
784: otext& print_smart_ptr_clone(otext& str, const smart_ptr_clone<T>& ptr, unsigned indent, std::string null_string);
785:
786: ////////////////////////////////////////////////////////////////////////////////
787: // persistence - call these rather than the methods
788: // the dump routine dumps smart_ptr_clone-specific information and then calls dump_interface
789: // similarly the restore routine calls restore_interface
790: // so therefore the class T should implement the persistent interface defined by the class persistent in persistent.hpp
791:
792: template<typename T>
793: void dump_smart_ptr_clone(dump_context& str, const smart_ptr_clone<T>& data) throw(persistent_dump_failed);
794:
795: template<typename T>
796: void restore_smart_ptr_clone(restore_context& str, smart_ptr_clone<T>& data) throw(persistent_restore_failed);
797:
798: ////////////////////////////////////////////////////////////////////////////////
799: ////////////////////////////////////////////////////////////////////////////////
800: // No-copy smart pointer class for managing objects that cannot be copied
801: ////////////////////////////////////////////////////////////////////////////////
802: ////////////////////////////////////////////////////////////////////////////////
803:
804: template<typename T>
805: class smart_ptr_nocopy
806: {
807: public:
808: //////////////////////////////////////////////////////////////////////////////
809: // member type definitions
810:
811: typedef T value_type;
812: typedef T& reference;
813: typedef const T& const_reference;
814:
815: //////////////////////////////////////////////////////////////////////////////
816: // constructors, assignments and destructors
817:
818: // create a null pointer
819: smart_ptr_nocopy(void);
820:
821: // copy constructor implements counted referencing - no copy is made
822: smart_ptr_nocopy(const smart_ptr_nocopy<T>& r);
823: // assignment of smart pointers implement counted referencing - no copy is made
824: smart_ptr_nocopy<T>& operator=(const smart_ptr_nocopy<T>&);
825:
826: // create a pointer containing a dynamically created object
827: // Note: the object must be allocated *by the user* with new
828: // constructor form - must be called in the form smart_ptr_nocopy<type> x(new type(args))
829: explicit smart_ptr_nocopy(T* data);
830: // assignment form
831: smart_ptr_nocopy<T>& operator= (T* data);
832:
833: // destructor decrements the reference count and delete only when the last reference is destroyed
834: ~smart_ptr_nocopy(void);
835:
836: //////////////////////////////////////////////////////////////////////////////
837: // logical tests to see if there is anything contained in the pointer since it can be null
838:
839: // there are two forms:explicit and implicit
840: // implicit: if(!r) or if(r)
841: // explicit: if(r.null()) or if(r.present())
842: operator bool(void) const;
843: bool operator!(void) const;
844: bool present(void) const;
845: bool null(void) const;
846:
847: //////////////////////////////////////////////////////////////////////////////
848: // dereference operators and functions
849:
850: // dereference the smart pointer to get the object - use in the form *p1
851: T& operator*(void) throw(null_dereference);
852: const T& operator*(void) const throw(null_dereference);
853:
854: // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
855: T* operator->(void) throw(null_dereference);
856: const T* operator->(void) const throw(null_dereference);
857:
858: //////////////////////////////////////////////////////////////////////////////
859: // explicit function forms of the above assignment and dereference operators
860:
861: // get the value
862: T& value(void) throw(null_dereference);
863: const T& value(void) const throw(null_dereference);
864:
865: // set the pointer
866: // deletes the previous pointer and adopts the passed pointer instead
867: // Note: the object must be allocated *by the user* with new
868: // Warning: it is very easy to break the memory management with this operation
869: void set(T* data = 0);
870: // get the pointer
871: T* pointer(void);
872: const T* pointer(void) const;
873:
874: //////////////////////////////////////////////////////////////////////////////
875: // functions to manage counted referencing
876:
877: // test whether two pointers point to the same object(known as aliasing the object)
878: // used in the form if(a.aliases(b))
879: bool aliases(const smart_ptr_nocopy<T>&) const;
880:
881: // find the number of aliases - used when you need to know whether an object is still referred to from elsewhere (rare!)
882: unsigned alias_count(void) const;
883:
884: // delete the object and make the pointer null - does not make it unique first, so all other pointers to this will be null too
885: void clear(void);
886:
887: // make the pointer unique and null in one step - does not affect other pointers that were pointing to the same object
888: void clear_unique(void);
889:
890: protected:
891: smart_ptr_holder<T>* m_holder;
892: };
893:
894: ////////////////////////////////////////////////////////////////////////////////
895: // comparisons required for using this class in an STL container
896: // These require == and < operator in the contained type T
897: // the remaining relational operators are provided by template functions
898: // a null pointer is less-than a non-null, two nulls are equal
899: // these funcions are defined as non-members so that you only need provide
900: // the underlying T::operator< and == if you are going to use these functions
901:
902: template<typename T>
903: bool operator==(const smart_ptr_nocopy<T>&, const smart_ptr_nocopy<T>&);
904:
905: template<typename T>
906: bool operator<(const smart_ptr_nocopy<T>&, const smart_ptr_nocopy<T>&);
907:
908: ////////////////////////////////////////////////////////////////////////////////
909: // string/print utilities
910:
911: template<typename T>
912: std::string smart_ptr_nocopy_to_string(const smart_ptr_nocopy<T>& ptr, std::string null_string);
913:
914: template<typename T>
915: otext& print_smart_ptr_nocopy(otext& str, const smart_ptr_nocopy<T>& ptr, std::string null_string);
916:
917: template<typename T>
918: otext& print_smart_ptr_nocopy(otext& str, const smart_ptr_nocopy<T>& ptr, unsigned indent, std::string null_string);
919:
920: ////////////////////////////////////////////////////////////////////////////////
921: // there's no persistence on smart_ptr_nocopy because the whole point is that
922: // it stores an uncopyable object and persistence is a form of copying
923:
924: ////////////////////////////////////////////////////////////////////////////////
925: #include "smart_ptr.tpp"
926: #endif