PVData C++ 8.0.7
Loading...
Searching...
No Matches
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
27#define HAVE_SHOW_REFS
28
29namespace epics {
30namespace debug {
31
32struct tracker;
33class shared_ptr_base;
34
35class 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;
41protected:
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
52public:
54 void show_refs(std::ostream&, bool self=true, bool weak=false) const;
55 void spy_refs(ref_set_t&) const;
56};
57
58class epicsShareClass weak_ptr_base : public ptr_base {
59protected:
60 weak_ptr_base() {}
61 weak_ptr_base(const track_t& track) :ptr_base(track) {}
62};
63
64class epicsShareClass shared_ptr_base : public ptr_base {
65protected:
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(const 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
93public:
94 void show_stack(std::ostream&) const;
95};
96
97
98
99template<typename T>
100class shared_ptr;
101template<typename T>
102class weak_ptr;
103template<class Base>
105
106template<typename Store, typename Actual>
107inline void
108do_enable_shared_from_this(const shared_ptr<Store>& dest,
110 );
111
112template<typename T>
113inline void
114do_enable_shared_from_this(const shared_ptr<T>&, ...) {}
115
116template<typename T>
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();}
131public:
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>
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,
223 );
224};
225
226template<typename TO, typename FROM>
228 return shared_ptr<TO>(std::static_pointer_cast<TO>(src.real), src.track);
229}
230
231template<typename TO, typename FROM>
232shared_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
236template<typename TO, typename FROM>
237shared_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
241template<typename T>
242class 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
252public:
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 bool expired() const noexcept { return real.expired(); }
290};
291
292template<class Base>
294 mutable weak_ptr<Base> xxInternalSelf;
295
296 template<typename Store, typename Actual>
297 friend
298 void
299 do_enable_shared_from_this(const shared_ptr<Store>& dest,
301 );
302public:
303 shared_ptr<Base> shared_from_this() const {
304 return shared_ptr<Base>(xxInternalSelf);
305 }
306};
307
308template<typename Store, typename Actual>
309inline void
310do_enable_shared_from_this(const shared_ptr<Store>& dest,
312 )
313{
314 shared_ptr<Actual> actual(dynamic_pointer_cast<Actual>(dest));
315 if(!actual)
316 throw std::logic_error("epics::debug::enabled_shared_from_this fails");
317 self->xxInternalSelf = actual;
318}
319
320template<typename T>
321inline std::ostream& operator<<(std::ostream& strm, const shared_ptr<T>& ptr)
322{
323 strm<<ptr.get();
324 return strm;
325}
326
327}} // namespace epics::debug
328#endif // DEBUGPTR_H
constexpr complex< _Tp > & operator=(const _Tp &)
void swap(shared_ptr< _Tp > &__a, shared_ptr< _Tp > &__b) noexcept
void swap(any &__x, any &__y) noexcept
__shared_ptr< _Tp, _Lp > dynamic_pointer_cast(const __shared_ptr< _Tp1, _Lp > &__r) noexcept
basic_ostream< _CharT, _Traits > & operator<<(basic_ostream< _CharT, _Traits > &__os, const basic_string< _CharT, _Traits, _Alloc > &__str)
__shared_ptr< _Tp, _Lp > static_pointer_cast(const __shared_ptr< _Tp1, _Lp > &__r) noexcept
__shared_ptr< _Tp, _Lp > const_pointer_cast(const __shared_ptr< _Tp1, _Lp > &__r) noexcept
typename __shared_ptr< _Tp >::element_type element_type
epics
Definition convert.h:21