vbl_smart_ptr.h
Go to the documentation of this file.
1 // This is core/vbl/vbl_smart_ptr.h
2 #ifndef vbl_smart_ptr_h_
3 #define vbl_smart_ptr_h_
4 //:
5 // \file
6 // \brief Contains a templated smart pointer class
7 // \author Richard Hartley (original Macro version),
8 // William A. Hoffman (current templated version)
9 //
10 // \verbatim
11 // Modifications
12 // 2000.05.15 Francois BERTEL Added some missing <T>
13 // 2000.05.16 Peter Vanroose Operators > < >= <= made const
14 // 2000.09.13 fsm Added rationale for unprotect().
15 // PDA (Manchester) 23/03/2001: Tidied up the documentation
16 // Peter Vanroose 27/05/2001: Corrected the documentation
17 // Feb.2002 - Peter Vanroose - brief doxygen comment placed on single line
18 // \endverbatim
19 
20 #include <iosfwd>
21 #ifdef _MSC_VER
22 # include <vcl_msvc_warnings.h>
23 #endif
24 
25 //: A templated smart pointer class
26 // This class requires that the class being templated over has
27 // the following signatures (methods) :
28 // \code
29 // void T::ref();
30 // void T::unref();
31 // \endcode
32 //
33 // By default, the vbl_smart_ptr<T> will ref() the object given
34 // to it upon construction and unref() it upon destruction. In
35 // some cases, however, it is useful to cause an unref() immediately
36 // and to avoid an unref() in the constructor. For example, in the
37 // cyclic data structure
38 // \code
39 // start -> A -> B -> C -> D -> E
40 // ^ |
41 // | |
42 // +-------------------+
43 // \endcode
44 //
45 // The refcounts on A, B, C, D, E are 2, 1, 1, 1, 1 so when 'start'
46 // goes out of scope, the refcount will be 1, 1, 1, 1, 1 and therefore
47 // the ring never gets deleted. Calling unprotect() on 'E' solves this
48 // as it effectively transfers ownership of 'A' from 'E' to 'start'.
49 //
50 // Although unprotect() can be handy, it should be used with care. It
51 // can sometimes (but not always) be avoided by assigning 0 (null pointer)
52 // to one of the nodes in the ring.
53 //
54 // See also vbl_ref_count
55 template <class T>
56 class vbl_smart_ptr
57 {
58  //: The protected flag says whether or not the object held will be unref()fed when the smart pointer goes out of scope.
59  bool protected_;
60 
61  //: Pointer to object, or 0.
62  T *ptr_;
63 
64  public:
66  : protected_(true), ptr_(nullptr) { }
67 
68  template<class Y>
70  : protected_(true), ptr_(p.as_pointer()) { if (ptr_) ref(ptr_); }
71 
73  : protected_(true), ptr_(p.as_pointer()) { if (ptr_) ref(ptr_); }
74 
76  : protected_(true), ptr_(p) { if (ptr_) ref(ptr_); }
77 
79  {
80  // the strange order of events in this function is to avoid
81  // heap corruption if unref() causes *this to be deleted.
82  if (protected_)
83  {
84  T *old_ptr = ptr_;
85  ptr_ = nullptr;
86  if (old_ptr)
87  unref(old_ptr);
88  }
89  else
90  ptr_ = nullptr;
91  }
92 
93  //: Assignment
95  {
96  return operator=(r.as_pointer());
97  }
98 
100  {
101  if (ptr_ != r)
102  {
103  // If there are circular references, calling unref() may
104  // cause *this to be destroyed and so assigning to 'ptr_'
105  // would be ill-formed and could cause heap corruption.
106  // Hence perform the unref() only at the very end.
107  T *old_ptr = ptr_;
108  ptr_ = r;
109 
110  if (ptr_)
111  ref(ptr_);
112 
113  // *this might get deleted now, but that's ok.
114  if (old_ptr && protected_)
115  unref(old_ptr);
116  }
117  protected_ = true;
118  return *this;
119  }
120 
121  //: Cast to bool
122  /* The old 'safe_bool' did implicit conversions, best practice would be to use explicit operator bool */
123  operator bool () const { return ptr_? true : false; }
124 
125  //: Inverse boolean value
126  bool operator!() const { return ptr_? false : true; }
127 
128  //: Dereferencing the pointer
129  T &operator * () const { return *ptr_; }
130 
131  //: These methods all return the raw/dumb pointer.
132  T *operator -> () const { return ptr_; }
133 
134  //: These methods all return the raw/dumb pointer.
135  T *ptr () const { return ptr_; }
136 
137  //: These methods all return the raw/dumb pointer.
138  //
139  // WARNING : Do not add an automatic cast to T*.
140  // This is intrinsically incorrect as you loose the smartness!
141  // In cases where you really need the pointer, it is better
142  // to be explicit about it and use one of the methods.
143  T *as_pointer () const { return ptr_; }
144 
145  //: Used for breaking circular references (see above).
146  void unprotect() {
147  if (protected_ && ptr_)
148  unref(ptr_);
149  protected_ = false;
150  }
151 
152  //: Is this smart pointer responsible for the object being pointed to
153  // If this value is false, the object does not have to save it.
154  bool is_protected() const { return protected_; }
155 
156 #if 0 // no longer needed
157  //: If a T_ref is converted to a pointer then back to a T_ref, you'll need to call this
158  void protect()
159  {
160  if (!protected_ && ptr_)
161  ref(ptr_);
162  protected_ = true;
163  }
164 #endif
165 
166  // Relational operators.
167  //There's no need for casts to void* or any other pointer type than T* here.
168 
169  //: Do a shallow equality
170  // Do they point to the same object.
171  bool operator==(T const *p) const { return ptr_ == p; }
172 
173  //: Do a shallow inequality
174  // Do the smart pointers not point to the same object.
175  bool operator!=(T const *p) const { return ptr_ != p; }
176 
177  //: Do a shallow equality
178  // Do they point to the same object.
179  bool operator==(vbl_smart_ptr<T>const&p)const{return ptr_ == p.as_pointer();}
180 
181  //: Do a shallow inequality
182  // Do the smart pointers not point to the same object.
183  bool operator!=(vbl_smart_ptr<T>const&p)const{return ptr_ != p.as_pointer();}
184  bool operator< (vbl_smart_ptr<T>const&p)const{return ptr_ < p.as_pointer();}
185  bool operator> (vbl_smart_ptr<T>const&p)const{return ptr_ > p.as_pointer();}
186  bool operator<=(vbl_smart_ptr<T>const&p)const{return ptr_ <= p.as_pointer();}
187  bool operator>=(vbl_smart_ptr<T>const&p)const{return ptr_ >= p.as_pointer();}
188 
189  private:
190  // These two methods should not be inlined as they call T's ref()
191  // and unref() or are specializations. The big gain from that is
192  // that vbl_smart_ptr<T> can be forward declared even if T is still
193  // an incomplete type.
194  static void ref (T *p);
195  static void unref(T *p);
196 };
197 
198 
199 //: Comparison of pointer with smart-pointer (cannot be a member function)
200 template <class T>
201 inline bool operator== (T const* p, vbl_smart_ptr<T> const& a)
202 {
203  return a.as_pointer() == p;
204 }
205 
206 template <class T>
207 inline bool operator!= (T const* p, vbl_smart_ptr<T> const& a)
208 {
209  return a.as_pointer() != p;
210 }
211 
212 // GCC need a std::ostream operator. It need not be inline
213 // because if you're about to make a system call you can afford the
214 // cost of a function call.
215 template <class T>
216 std::ostream& operator<< (std::ostream&, vbl_smart_ptr<T> const&);
217 
218 #define VBL_SMART_PTR_INSTANTIATE(T) \
219 extern "please include vbl/vbl_smart_ptr.hxx instead"
220 
221 #endif // vbl_smart_ptr_h_
bool operator==(T const *p, vbl_smart_ptr< T > const &a)
Comparison of pointer with smart-pointer (cannot be a member function).
bool operator!=(vbl_smart_ptr< T >const &p) const
Do a shallow inequality.
T & operator *() const
Dereferencing the pointer.
T * as_pointer() const
These methods all return the raw/dumb pointer.
static void ref(T *p)
vbl_smart_ptr(vbl_smart_ptr< T > const &p)
Definition: vbl_smart_ptr.h:72
bool is_protected() const
Is this smart pointer responsible for the object being pointed to.
std::ostream & operator<<(std::ostream &, vbl_smart_ptr< T > const &)
void unprotect()
Used for breaking circular references (see above).
bool operator!=(T const *p) const
Do a shallow inequality.
T * ptr_
Pointer to object, or 0.
Definition: vbl_smart_ptr.h:62
A templated smart pointer class.
Definition: vbl_fwd.h:18
vbl_smart_ptr(T *p)
Definition: vbl_smart_ptr.h:75
bool operator<(vbl_smart_ptr< T >const &p) const
bool operator!=(T const *p, vbl_smart_ptr< T > const &a)
vbl_smart_ptr< T > & operator=(vbl_smart_ptr< T > const &r)
Assignment.
Definition: vbl_smart_ptr.h:94
static void unref(T *p)
vbl_smart_ptr(vbl_smart_ptr< Y > const &p)
Definition: vbl_smart_ptr.h:69
bool operator>(vbl_smart_ptr< T >const &p) const
bool operator<=(vbl_smart_ptr< T >const &p) const
bool operator==(T const *p) const
Do a shallow equality.
bool operator!() const
Inverse boolean value.
bool protected_
The protected flag says whether or not the object held will be unref()fed when the smart pointer goes...
Definition: vbl_smart_ptr.h:59
bool operator>=(vbl_smart_ptr< T >const &p) const
T * ptr() const
These methods all return the raw/dumb pointer.
bool operator==(vbl_smart_ptr< T >const &p) const
Do a shallow equality.
T * operator ->() const
These methods all return the raw/dumb pointer.