PVData C++  8.0.3
debugPtr.h
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 
25 //! User code should test this macro
26 //! before calling epics::debug::shared_ptr::show_refs()
27 #define HAVE_SHOW_REFS
28 
29 namespace epics {
30 namespace debug {
31 
32 struct tracker;
33 class shared_ptr_base;
34 
35 class epicsShareClass ptr_base {
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 
58 class epicsShareClass weak_ptr_base : public ptr_base {
59 protected:
60  weak_ptr_base() {}
61  weak_ptr_base(const track_t& track) :ptr_base(track) {}
62 };
63 
64 class epicsShareClass shared_ptr_base : public ptr_base {
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>
100 class shared_ptr;
101 template<typename T>
102 class weak_ptr;
103 template<class Base>
104 class enable_shared_from_this;
105 
106 template<typename Store, typename Actual>
107 inline void
108 do_enable_shared_from_this(const shared_ptr<Store>& dest,
109  enable_shared_from_this<Actual>* self
110  );
111 
112 template<typename T>
113 inline void
114 do_enable_shared_from_this(const shared_ptr<T>&, ...) {}
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:
132  typedef typename real_type::element_type element_type;
133  typedef weak_ptr<T> weak_type;
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 
158  ~shared_ptr() {}
159 
160  shared_ptr& operator=(const shared_ptr& o) {
161  if(this!=&o) {
162  real = o.real;
163  track_assign(o);
164  }
165  return *this;
166  }
167  template<typename A>
168  shared_ptr& operator=(const shared_ptr<A>& o) {
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);
188  shared_ptr_base::swap(o);
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
212  shared_ptr<TO> static_pointer_cast(const shared_ptr<FROM>& src);
213  template<typename TO, typename FROM>
214  friend
215  shared_ptr<TO> const_pointer_cast(const shared_ptr<FROM>& src);
216  template<typename TO, typename FROM>
217  friend
218  shared_ptr<TO> dynamic_pointer_cast(const shared_ptr<FROM>& src);
219  template<typename Store, typename Actual>
220  friend void
221  do_enable_shared_from_this(const shared_ptr<Store>& dest,
222  enable_shared_from_this<Actual>* self
223  );
224 };
225 
226 template<typename TO, typename FROM>
227 shared_ptr<TO> static_pointer_cast(const shared_ptr<FROM>& src) {
228  return shared_ptr<TO>(std::static_pointer_cast<TO>(src.real), src.track);
229 }
230 
231 template<typename TO, typename FROM>
232 shared_ptr<TO> const_pointer_cast(const shared_ptr<FROM>& src) {
233  return shared_ptr<TO>(std::const_pointer_cast<TO>(src.real), src.track);
234 }
235 
236 template<typename TO, typename FROM>
237 shared_ptr<TO> dynamic_pointer_cast(const shared_ptr<FROM>& src) {
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:
253  typedef typename real_type::element_type element_type;
254  typedef weak_ptr<T> weak_type;
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 
268  ~weak_ptr() {}
269 
270  weak_ptr& operator=(const weak_ptr& o) {
271  if(this!=&o) {
272  real = o.real;
273  track = o.track;
274  }
275  return *this;
276  }
277  template<typename A>
278  weak_ptr& operator=(const shared_ptr<A>& o) {
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>
292 class enable_shared_from_this {
293  mutable weak_ptr<Base> xxInternalSelf;
294 
295  template<typename Store, typename Actual>
296  friend
297  void
298  do_enable_shared_from_this(const shared_ptr<Store>& dest,
299  enable_shared_from_this<Actual>* self
300  );
301 public:
302  shared_ptr<Base> shared_from_this() const {
303  return shared_ptr<Base>(xxInternalSelf);
304  }
305 };
306 
307 template<typename Store, typename Actual>
308 inline void
309 do_enable_shared_from_this(const shared_ptr<Store>& dest,
310  enable_shared_from_this<Actual>* self
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
#define EXCEPT_DEPTH