Panda3D
Loading...
Searching...
No Matches
referenceCount.I
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file referenceCount.I
10 * @author drose
11 * @date 1998-10-23
12 */
13
14template<class Base>
16
17template<class Base>
19
20/**
21 * The ReferenceCount constructor is protected because you almost never want
22 * to create just a ReferenceCount object by itself, and it's probably a
23 * mistake if you try.
24 *
25 * ReferenceCount doesn't store any useful information in its own right; its
26 * only purpose is to add reference-counting to some other class via
27 * inheritance.
28 */
29INLINE ReferenceCount::
30ReferenceCount() {
31 _weak_list = nullptr;
32 _ref_count = 0;
33#ifdef DO_MEMORY_USAGE
35#endif
36}
37
38/**
39 * The copies of reference-counted objects do not themselves inherit the
40 * reference count!
41 *
42 * This copy constructor is protected because you almost never want to create
43 * just a ReferenceCount object by itself, and it's probably a mistake if you
44 * try.
45 */
46INLINE ReferenceCount::
47ReferenceCount(const ReferenceCount &) {
48 _weak_list = nullptr;
49 _ref_count = 0;
50#ifdef DO_MEMORY_USAGE
52#endif
53}
54
55/**
56 * The copies of reference-counted objects do not themselves inherit the
57 * reference count!
58 *
59 * This copy assignment operator is protected because you almost never want to
60 * copy just a ReferenceCount object by itself, and it's probably a mistake if
61 * you try. Instead, this should only be called from a derived class that
62 * implements this operator and then calls up the inheritance chain.
63 */
64INLINE void ReferenceCount::
65operator = (const ReferenceCount &) {
66 // If this assertion fails, our own pointer was recently deleted. Possibly
67 // you used a real pointer instead of a PointerTo at some point, and the
68 // object was deleted when the PointerTo went out of scope. Maybe you tried
69 // to create an automatic (local variable) instance of a class that derives
70 // from ReferenceCount. Or maybe your headers are out of sync, and you need
71 // to make clean in direct or some higher tree.
72 nassertv(_ref_count != deleted_ref_count);
73}
74
75/**
76 *
77 */
78ReferenceCount::
79~ReferenceCount() {
80 TAU_PROFILE("ReferenceCount::~ReferenceCount()", " ", TAU_USER);
81 // If this assertion fails, we're trying to delete an object that was just
82 // deleted. Possibly you used a real pointer instead of a PointerTo at some
83 // point, and the object was deleted when the PointerTo went out of scope.
84 // Maybe you tried to create an automatic (local variable) instance of a
85 // class that derives from ReferenceCount. Or maybe your headers are out of
86 // sync, and you need to make clean in direct or some higher tree.
87 nassertv(_ref_count != deleted_ref_count);
88
89 // If this assertion fails, we're trying to delete a static object that
90 // still has an outstanding reference count. You should make sure that all
91 // references to your static objects are gone by the time the object itself
92 // destructs.
93 nassertv(_ref_count <= local_ref_count);
94
95 // If this assertion fails, the reference counts are all screwed up
96 // altogether. Maybe some errant code stomped all over memory somewhere.
97 nassertv(_ref_count >= 0);
98
99 // If this assertion fails, someone tried to delete this object while its
100 // reference count was still positive. Maybe you tried to point a PointerTo
101 // at a static object (a local variable, instead of one allocated via new)?
102 // The test below against 0x7f is supposed to check for that, but it's a
103 // pretty hokey test.
104
105 // Another possibility is you inadvertently omitted a copy constructor for a
106 // ReferenceCount object, and then bitwise copied a dynamically allocated
107 // value--reference count and all--onto a locally allocated one.
108 nassertv(_ref_count == 0 || _ref_count == local_ref_count);
109
110 // Tell our weak reference holders that we're going away now.
111 if (_weak_list != nullptr) {
112 ((WeakReferenceList *)_weak_list)->mark_deleted();
113 _weak_list = nullptr;
114 }
115
116#ifndef NDEBUG
117 // Ok, all clear to delete. Now set the reference count to
118 // deleted_ref_count, so we'll have a better chance of noticing if we happen
119 // to have a stray pointer to it still out there.
120 _ref_count = deleted_ref_count;
121#endif
122
123#ifdef DO_MEMORY_USAGE
125#endif
126}
127
128/**
129 * Returns the current reference count.
130 */
131INLINE int ReferenceCount::
132get_ref_count() const {
133#ifdef _DEBUG
135#endif
136 return (int)AtomicAdjust::get(_ref_count);
137}
138
139/**
140 * Explicitly increments the reference count. User code should avoid using
141 * ref() and unref() directly, which can result in missed reference counts.
142 * Instead, let a PointerTo object manage the reference counting
143 * automatically.
144 *
145 * This function is const, even though it changes the object, because
146 * generally fiddling with an object's reference count isn't considered part
147 * of fiddling with the object. An object might be const in other ways, but
148 * we still need to accurately count the number of references to it.
149 */
151ref() const {
152 TAU_PROFILE("void ReferenceCount::ref()", " ", TAU_USER);
153#ifdef _DEBUG
154 nassertv(test_ref_count_integrity());
155#endif
156
157 AtomicAdjust::inc(_ref_count);
158}
159
160/**
161 * Explicitly decrements the reference count. Note that the object will not
162 * be implicitly deleted by unref() simply because the reference count drops
163 * to zero. (Having a member function delete itself is problematic.) However,
164 * see the helper function unref_delete().
165 *
166 * User code should avoid using ref() and unref() directly, which can result
167 * in missed reference counts. Instead, let a PointerTo object manage the
168 * reference counting automatically.
169 *
170 * This function is const, even though it changes the object, because
171 * generally fiddling with an object's reference count isn't considered part
172 * of fiddling with the object. An object might be const in other ways, but
173 * we still need to accurately count the number of references to it.
174 *
175 * The return value is true if the new reference count is nonzero, false if it
176 * is zero.
177 */
179unref() const {
180 TAU_PROFILE("void ReferenceCount::unref()", " ", TAU_USER);
181#ifdef _DEBUG
182 nassertr(test_ref_count_integrity(), 0);
183
184 // If this assertion fails, you tried to unref an object with a zero
185 // reference count. Are you using ref() and unref() directly? Are you sure
186 // you can't use PointerTo's?
187 nassertr(_ref_count > 0, 0);
188#endif
189 return AtomicAdjust::dec(_ref_count);
190}
191
192/**
193 * Does some easy checks to make sure that the reference count isn't
194 * completely bogus. Returns true if ok, false otherwise.
195 */
198#ifndef NDEBUG
199 return do_test_ref_count_integrity();
200#else
201 return true;
202#endif
203}
204
205/**
206 * Does some easy checks to make sure that the reference count isn't zero, or
207 * completely bogus. Returns true if ok, false otherwise.
208 */
211#ifndef NDEBUG
212 return do_test_ref_count_nonzero();
213#else
214 return true;
215#endif
216}
217
218/**
219 * This function should be called, once, immediately after creating a new
220 * instance of some ReferenceCount-derived object on the stack.
221 *
222 * This allows the object to be passed to functions that will increment and
223 * decrement the object's reference count temporarily, and it will prevent the
224 * object from being deleted (inappropriately), when the reference count
225 * returns to zero. It actually achieves this by setting a large positive
226 * value in the reference count field.
227 */
229local_object() {
230 // If this assertion fails, you didn't call this immediately after creating
231 // a local object.
232 nassertv(_ref_count == 0);
233
234 _ref_count = local_ref_count;
235}
236
237/**
238 * Returns true if this particular ReferenceCount object has a
239 * WeakReferenceList created, false otherwise. In general, this will be true
240 * if there was ever a WeakPointerTo created for this object (even if there is
241 * not any for it now).
242 */
244has_weak_list() const {
245 return _weak_list != nullptr;
246}
247
248/**
249 * Returns the WeakReferenceList associated with this ReferenceCount object.
250 * If there has never been a WeakReferenceList associated with this object,
251 * creates one now.
252 *
253 * The returned object will be deleted automatically when all weak and strong
254 * references to the object have gone.
255 */
257get_weak_list() const {
258 if (AtomicAdjust::get_ptr(_weak_list) == nullptr) {
259 ((ReferenceCount *)this)->create_weak_list();
260 }
261 return (WeakReferenceList *)AtomicAdjust::get_ptr(_weak_list);
262}
263
264/**
265 * Adds the indicated PointerToVoid as a weak reference to this object.
266 * Returns an object that will persist as long as any reference (strong or
267 * weak) exists, for calling unref() or checking whether the object still
268 * exists.
269 */
271weak_ref() {
272 TAU_PROFILE("void ReferenceCount::weak_ref()", " ", TAU_USER);
273#ifdef _DEBUG
274 nassertr(test_ref_count_integrity(), nullptr);
275#else
276 nassertr(_ref_count != deleted_ref_count, nullptr);
277#endif
279 weak_ref->ref();
280 return weak_ref;
281}
282
283/**
284 * Removes the indicated PointerToVoid as a weak reference to this object. It
285 * must have previously been added via a call to weak_ref().
286 */
288weak_unref() {
289 TAU_PROFILE("void ReferenceCount::weak_unref()", " ", TAU_USER);
290#ifdef _DEBUG
291 nassertv(test_ref_count_integrity());
292#endif
293 WeakReferenceList *weak_list = (WeakReferenceList *)_weak_list;
294 nassertv(weak_list != nullptr);
295 bool nonzero = weak_list->unref();
296 nassertv(nonzero);
297}
298
299/**
300 * Atomically increases the reference count of this object if it is not zero.
301 * Do not use this. This exists only to implement a special case for weak
302 * pointers.
303 * @return true if the reference count was incremented, false if it was zero.
304 */
306ref_if_nonzero() const {
307#ifdef _DEBUG
309#endif
310 AtomicAdjust::Integer ref_count;
311 do {
312 ref_count = AtomicAdjust::get(_ref_count);
313 if (ref_count <= 0) {
314 return false;
315 }
316 } while (ref_count != AtomicAdjust::compare_and_exchange(_ref_count, ref_count, ref_count + 1));
317 return true;
318}
319
320/**
321 * Atomically decreases the reference count of this object if it is one.
322 * Do not use this. This exists only to implement a special case with the
323 * state cache.
324 * @return false if the reference count was decremented to zero.
325 */
327unref_if_one() const {
328#ifdef _DEBUG
329 nassertr(test_ref_count_integrity(), 0);
330 nassertr(_ref_count > 0, 0);
331#endif
332 return (AtomicAdjust::compare_and_exchange(_ref_count, 1, 0) != 1);
333}
334
335/**
336 * This global helper function will unref the given ReferenceCount object, and
337 * if the reference count reaches zero, automatically delete it. It can't be
338 * a member function because it's usually a bad idea to delete an object from
339 * within its own member function. It's a template function so the destructor
340 * doesn't have to be virtual.
341 */
342template<class RefCountType>
343INLINE void
344unref_delete(RefCountType *ptr) {
345 TAU_PROFILE("void unref_delete(RefCountType *)", " ", TAU_USER);
346 // Although it may be tempting to try to upcast ptr to a ReferenceCount
347 // object (particularly to get around inheritance issues), resist that
348 // temptation, since some classes (in particular, TransformState and
349 // RenderState) rely on a non-virtual overloading of the unref() method.
350
351 if (!ptr->unref()) {
352 // If the reference count has gone to zero, delete the object.
353 delete ptr;
354 }
355}
356
357/**
358 *
359 */
360template<class Base>
363}
364
365/**
366 *
367 */
368template<class Base>
370RefCountProxy(const Base &copy) : _base(copy) {
371}
372
373/**
374 *
375 */
376template<class Base>
377INLINE RefCountProxy<Base>::
378operator Base &() {
379 return _base;
380}
381
382/**
383 *
384 */
385template<class Base>
386INLINE RefCountProxy<Base>::
387operator const Base &() const {
388 return _base;
389}
390
391/**
392 *
393 */
394template<class Base>
396init_type() {
397 do_init_type(Base);
398 register_type(_type_handle,
399 "RefCountProxy<" + get_type_handle(Base).get_name() + ">",
400 get_type_handle(Base));
401}
402
403
404/**
405 *
406 */
407template<class Base>
409RefCountObj() {
410}
411
412/**
413 *
414 */
415template<class Base>
417RefCountObj(const Base &copy) : Base(copy) {
418}
419
420
421/**
422 *
423 */
424template<class Base>
426init_type() {
427#if defined(HAVE_RTTI) && !defined(__EDG__) && (!defined(__GNUC__) || defined(__GXX_RTTI))
428 // If we have RTTI, we can determine the name of the base type.
429 std::string base_name = typeid(Base).name();
430#else
431 std::string base_name = "unknown";
432#endif
433
434 TypeHandle base_type = register_dynamic_type(base_name);
435
436 ReferenceCount::init_type();
437 _type_handle =
438 register_dynamic_type("RefCountObj<" + base_name + ">",
439 base_type, ReferenceCount::get_class_type());
440}
static bool dec(Integer &var)
Atomically decrements the indicated variable and returns true if the new value is nonzero,...
static Integer compare_and_exchange(Integer &mem, Integer old_value, Integer new_value)
Atomic compare and exchange.
static void inc(Integer &var)
Atomically increments the indicated variable.
static Pointer get_ptr(const Pointer &var)
Atomically retrieves the snapshot value of the indicated variable.
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
static void record_pointer(ReferenceCount *ptr)
Indicates that the given pointer has been recently allocated.
Definition memoryUsage.I:32
static void remove_pointer(ReferenceCount *ptr)
Indicates that the given pointer has been recently freed.
Definition memoryUsage.I:90
Another kind of proxy, similar to RefCountProxy.
A "proxy" to use to make a reference-countable object whenever the object cannot inherit from Referen...
A base class for all things that want to be reference-counted.
void ref() const
Explicitly increments the reference count.
WeakReferenceList * get_weak_list() const
Returns the WeakReferenceList associated with this ReferenceCount object.
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
bool ref_if_nonzero() const
Atomically increases the reference count of this object if it is not zero.
bool unref_if_one() const
Atomically decreases the reference count of this object if it is one.
get_ref_count
Returns the current reference count.
virtual bool unref() const
Explicitly decrements the reference count.
WeakReferenceList * weak_ref()
Adds the indicated PointerToVoid as a weak reference to this object.
bool has_weak_list() const
Returns true if this particular ReferenceCount object has a WeakReferenceList created,...
bool test_ref_count_nonzero() const
Does some easy checks to make sure that the reference count isn't zero, or completely bogus.
void weak_unref()
Removes the indicated PointerToVoid as a weak reference to this object.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This is an object shared by all the weak pointers that point to the same ReferenceCount object.
void ref() const
Increases the number of weak references.
bool unref() const
Decreases the number of weak references.
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
TypeHandle register_dynamic_type(const std::string &name)
This is essentially similar to register_type(), except that it doesn't store a reference to any TypeH...