This is Unofficial EPICS BASE Doxygen Site
debugPtr.h
Go to the documentation of this file.
1 /*
2  * Copyright information and license terms for this software can be
3  * found in the file LICENSE that is included with the distribution
4  */
5 /* Author: Michael Davidsaver */
6 /* wrapper around shared_ptr which tracks backwards references.
7  * Can help to find ref. leaks, loops, and other exciting bugs.
8  * See comments in sharedPtr.h
9  */
10 #ifndef DEBUGPTR_H
11 #define DEBUGPTR_H
12 
13 #if __cplusplus<201103L
14 # error c++11 required
15 #endif
16 
17 #include <ostream>
18 #include <memory>
19 #include <set>
20 
21 #include <pv/epicsException.h>
22 
23 #include <shareLib.h>
24 
27 #define HAVE_SHOW_REFS
28 
29 namespace epics {
30 namespace debug {
31 
32 struct tracker;
33 class shared_ptr_base;
34 
36  friend class shared_ptr_base;
37  template<typename A>
38  friend class shared_ptr;
39  template<typename A>
40  friend class weak_ptr;
41 protected:
42  typedef std::shared_ptr<tracker> track_t;
43  track_t track;
44 
45  ptr_base() noexcept : track() {}
46  ptr_base(const track_t& track) :track(track) {}
47  ptr_base(const ptr_base&) = delete;
48  ptr_base(ptr_base&&) = delete;
49 
50  ptr_base& operator=(const ptr_base&) = delete;
51 
52 public:
53  typedef std::set<const shared_ptr_base *> ref_set_t;
54  void show_refs(std::ostream&, bool self=true, bool weak=false) const;
55  void spy_refs(ref_set_t&) const;
56 };
57 
59 protected:
61  weak_ptr_base(const track_t& track) :ptr_base(track) {}
62 };
63 
65 protected:
66  shared_ptr_base() noexcept
67 #ifndef EXCEPT_USE_NONE
68  :m_stack(), m_depth(0)
69 #endif
70  {}
71  shared_ptr_base(const track_t& track) :ptr_base(track)
72  #ifndef EXCEPT_USE_NONE
73  ,m_stack(), m_depth(0)
74  #endif
75  {}
76  ~shared_ptr_base() {track_clear();}
77 
78  // add ourselves to tracker
79  void track_new();
80  // create new tracker if ptr!=nullptr, otherwise clear
81  void track_new(void* ptr);
82  // copy tracker and add ourself
83  void track_assign(const shared_ptr_base& o);
84  void track_clear();
85  void swap(shared_ptr_base& o);
86  void snap_stack();
87 
88 #ifndef EXCEPT_USE_NONE
89  void *m_stack[EXCEPT_DEPTH];
90  int m_depth; // always <= EXCEPT_DEPTH
91 #endif
92 
93 public:
94  void show_stack(std::ostream&) const;
95 };
96 
97 
98 
99 template<typename T>
101 template<typename T>
102 class weak_ptr;
103 template<class Base>
105 
106 template<typename Store, typename Actual>
107 inline void
110  );
111 
112 template<typename T>
113 inline void
115 
116 template<typename T>
117 class shared_ptr : public shared_ptr_base {
118  typedef ::std::shared_ptr<T> real_type;
119 
120  real_type real;
121 
122  template<typename A>
123  friend class shared_ptr;
124  template<typename A>
125  friend class weak_ptr;
126 
127  // ctor for casts
128  shared_ptr(const real_type& r, const ptr_base::track_t& t)
129  :shared_ptr_base(t), real(r)
130  {track_new();}
131 public:
134 
135  // new NULL
136  shared_ptr() noexcept {}
137  // copy existing same type
138  shared_ptr(const shared_ptr& o) :shared_ptr_base(o.track), real(o.real) {track_new();}
139  // copy existing of implicitly castable type
140  template<typename A>
141  shared_ptr(const shared_ptr<A>& o) :shared_ptr_base(o.track), real(o.real) {track_new();}
142 
143  // construct around new pointer
144  template<typename A, class ... Args>
145  explicit shared_ptr(A* a, Args ... args) : shared_ptr_base(), real(a, args...) {
146  track_new(a);
147  do_enable_shared_from_this(*this, a);
148  }
149 
150  // make strong ref from weak
151  template<typename A>
152  shared_ptr(const weak_ptr<A>& o) :shared_ptr_base(o.track), real(o.real) {track_new();}
153 
154  // takeover from unique_ptr
155  template<typename A>
156  shared_ptr(std::unique_ptr<A>&& a) : shared_ptr_base(), real(a.release()) {track_new();}
157 
159 
161  if(this!=&o) {
162  real = o.real;
163  track_assign(o);
164  }
165  return *this;
166  }
167  template<typename A>
169  if(get()!=o.get()) {
170  real = o.real;
171  track_assign(o);
172  }
173  return *this;
174  }
175 
176  void reset() noexcept { real.reset(); track_clear(); }
177  template<typename A, class ... Args>
178  void reset(A* a, Args ... args)
179  {
180  real.reset(a, args...);
181  track_new(a);
182  do_enable_shared_from_this(*this, a);
183  }
184  void swap(shared_ptr &o) noexcept
185  {
186  if(this!=&o) {
187  real.swap(o.real);
189  }
190  }
191 
192  // proxy remaining to underlying shared_ptr
193 
194  T* get() const noexcept { return real.get(); }
195  typename std::add_lvalue_reference<T>::type operator*() const noexcept { return *real; }
196  T* operator->() const noexcept { return real.get(); }
197  long use_count() const noexcept { return real.use_count(); }
198  bool unique() const noexcept { return real.unique(); }
199  explicit operator bool() const noexcept { return bool(real); }
200 
201  bool operator==(const shared_ptr<T>& o) const { return real==o.real; }
202  bool operator!=(const shared_ptr<T>& o) const { return real!=o.real; }
203  bool operator<(const shared_ptr<T>& o) const { return real<o.real; }
204 
205  template<typename A>
206  bool owner_before(const shared_ptr<A>& o) { return real.owner_before(o); }
207  template<typename A>
208  bool owner_before(const weak_ptr<A>& o) { return real.owner_before(o); }
209 
210  template<typename TO, typename FROM>
211  friend
213  template<typename TO, typename FROM>
214  friend
216  template<typename TO, typename FROM>
217  friend
219  template<typename Store, typename Actual>
220  friend void
223  );
224 };
225 
226 template<typename TO, typename FROM>
228  return shared_ptr<TO>(std::static_pointer_cast<TO>(src.real), src.track);
229 }
230 
231 template<typename TO, typename FROM>
233  return shared_ptr<TO>(std::const_pointer_cast<TO>(src.real), src.track);
234 }
235 
236 template<typename TO, typename FROM>
238  return shared_ptr<TO>(std::dynamic_pointer_cast<TO>(src.real), src.track);
239 }
240 
241 template<typename T>
242 class weak_ptr : public weak_ptr_base {
243  typedef ::std::weak_ptr<T> real_type;
244 
245  real_type real;
246 
247  template<typename A>
248  friend class shared_ptr;
249  template<typename A>
250  friend class weak_ptr;
251 
252 public:
255 
256  // new NULL
257  weak_ptr() noexcept {}
258  // copy existing same type
259  weak_ptr(const weak_ptr& o) :weak_ptr_base(o.track), real(o.real) {}
260  // copy existing of similar type
261  template<typename A>
262  weak_ptr(const weak_ptr<A>& o) :weak_ptr_base(o.track), real(o.real) {}
263 
264  // create week ref from strong ref
265  template<typename A>
266  weak_ptr(const shared_ptr<A>& o) :weak_ptr_base(o.track), real(o.real) {}
267 
269 
271  if(this!=&o) {
272  real = o.real;
273  track = o.track;
274  }
275  return *this;
276  }
277  template<typename A>
279  real = o.real;
280  track = o.track;
281  return *this;
282  }
283 
284  shared_ptr<T> lock() const noexcept { return shared_ptr<T>(real.lock(), track); }
285  void reset() noexcept { track.reset(); real.reset(); }
286 
287  long use_count() const noexcept { return real.use_count(); }
288  bool unique() const noexcept { return real.unique(); }
289 };
290 
291 template<class Base>
293  mutable weak_ptr<Base> xxInternalSelf;
294 
295  template<typename Store, typename Actual>
296  friend
297  void
300  );
301 public:
303  return shared_ptr<Base>(xxInternalSelf);
304  }
305 };
306 
307 template<typename Store, typename Actual>
308 inline void
311  )
312 {
313  shared_ptr<Actual> actual(dynamic_pointer_cast<Actual>(dest));
314  if(!actual)
315  throw std::logic_error("epics::debug::enabled_shared_from_this fails");
316  self->xxInternalSelf = actual;
317 }
318 
319 }} // namespace epics::debug
320 
321 template<typename T>
322 inline std::ostream& operator<<(std::ostream& strm, const epics::debug::shared_ptr<T>& ptr)
323 {
324  strm<<ptr.get();
325  return strm;
326 }
327 
328 #endif // DEBUGPTR_H
void reset() noexcept
Definition: debugPtr.h:285
void swap(shared_ptr_base &o)
shared_ptr< TO > static_pointer_cast(const shared_ptr< FROM > &src)
Definition: debugPtr.h:227
shared_ptr_base(const track_t &track)
Definition: debugPtr.h:71
#define EXCEPT_DEPTH
bool operator!=(const shared_ptr< T > &o) const
Definition: debugPtr.h:202
shared_ptr(std::unique_ptr< A > &&a)
Definition: debugPtr.h:156
void swap(shared_ptr &o) noexcept
Definition: debugPtr.h:184
weak_ptr< T > weak_type
Definition: debugPtr.h:133
pvd::StructureConstPtr type
shared_ptr< T > lock() const noexcept
Definition: debugPtr.h:284
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
real_type::element_type element_type
Definition: debugPtr.h:253
Mark external symbols and entry points for shared libraries.
shared_ptr & operator=(const shared_ptr &o)
Definition: debugPtr.h:160
void reset(A *a, Args...args)
Definition: debugPtr.h:178
void do_enable_shared_from_this(const shared_ptr< Store > &dest, enable_shared_from_this< Actual > *self)
Definition: debugPtr.h:309
shared_ptr(const shared_ptr &o)
Definition: debugPtr.h:138
bool unique() const noexcept
Definition: debugPtr.h:288
long use_count() const noexcept
Definition: debugPtr.h:197
shared_ptr(A *a, Args...args)
Definition: debugPtr.h:145
shared_ptr(const shared_ptr< A > &o)
Definition: debugPtr.h:141
bool owner_before(const shared_ptr< A > &o)
Definition: debugPtr.h:206
bool unique() const noexcept
Definition: debugPtr.h:198
shared_ptr< TO > dynamic_pointer_cast(const shared_ptr< FROM > &src)
Definition: debugPtr.h:237
bool owner_before(const weak_ptr< A > &o)
Definition: debugPtr.h:208
long use_count() const noexcept
Definition: debugPtr.h:287
std::set< const shared_ptr_base * > ref_set_t
Definition: debugPtr.h:53
weak_ptr(const weak_ptr< A > &o)
Definition: debugPtr.h:262
ptr_base(const track_t &track)
Definition: debugPtr.h:46
bool operator==(const shared_ptr< T > &o) const
Definition: debugPtr.h:201
ptr_base() noexcept
Definition: debugPtr.h:45
#define epicsShareClass
Definition: shareLib.h:206
weak_ptr & operator=(const shared_ptr< A > &o)
Definition: debugPtr.h:278
std::shared_ptr< tracker > track_t
Definition: debugPtr.h:42
weak_ptr() noexcept
Definition: debugPtr.h:257
shared_ptr(const weak_ptr< A > &o)
Definition: debugPtr.h:152
real_type::element_type element_type
Definition: debugPtr.h:132
weak_ptr< T > weak_type
Definition: debugPtr.h:254
shared_ptr< TO > const_pointer_cast(const shared_ptr< FROM > &src)
Definition: debugPtr.h:232
weak_ptr(const weak_ptr &o)
Definition: debugPtr.h:259
shared_ptr< Base > shared_from_this() const
Definition: debugPtr.h:302
shared_ptr & operator=(const shared_ptr< A > &o)
Definition: debugPtr.h:168
std::add_lvalue_reference< T >::type operator*() const noexcept
Definition: debugPtr.h:195
element_type
Definition: postfix.c:33
T * get() const noexcept
Definition: debugPtr.h:194
void reset() noexcept
Definition: debugPtr.h:176
weak_ptr_base(const track_t &track)
Definition: debugPtr.h:61
weak_ptr & operator=(const weak_ptr &o)
Definition: debugPtr.h:270
T * operator->() const noexcept
Definition: debugPtr.h:196
weak_ptr(const shared_ptr< A > &o)
Definition: debugPtr.h:266
#define EXCEPT_USE_NONE