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