Panda3D
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 
14 template<class Base>
16 
17 template<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  */
29 INLINE ReferenceCount::
30 ReferenceCount() {
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  */
46 INLINE ReferenceCount::
47 ReferenceCount(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  */
64 INLINE void ReferenceCount::
65 operator = (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  */
78 ReferenceCount::
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  */
131 INLINE int ReferenceCount::
132 get_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  */
150 INLINE void ReferenceCount::
151 ref() 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  */
178 INLINE bool ReferenceCount::
179 unref() 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  */
196 INLINE bool ReferenceCount::
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  */
209 INLINE bool ReferenceCount::
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  */
228 INLINE void ReferenceCount::
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  */
243 INLINE bool ReferenceCount::
244 has_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  */
257 get_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  */
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  */
287 INLINE void ReferenceCount::
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  */
305 INLINE bool ReferenceCount::
306 ref_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  * This global helper function will unref the given ReferenceCount object, and
322  * if the reference count reaches zero, automatically delete it. It can't be
323  * a member function because it's usually a bad idea to delete an object from
324  * within its own member function. It's a template function so the destructor
325  * doesn't have to be virtual.
326  */
327 template<class RefCountType>
328 INLINE void
329 unref_delete(RefCountType *ptr) {
330  TAU_PROFILE("void unref_delete(RefCountType *)", " ", TAU_USER);
331  // Although it may be tempting to try to upcast ptr to a ReferenceCount
332  // object (particularly to get around inheritance issues), resist that
333  // temptation, since some classes (in particular, TransformState and
334  // RenderState) rely on a non-virtual overloading of the unref() method.
335 
336  if (!ptr->unref()) {
337  // If the reference count has gone to zero, delete the object.
338  delete ptr;
339  }
340 }
341 
342 /**
343  *
344  */
345 template<class Base>
347 RefCountProxy() {
348 }
349 
350 /**
351  *
352  */
353 template<class Base>
355 RefCountProxy(const Base &copy) : _base(copy) {
356 }
357 
358 /**
359  *
360  */
361 template<class Base>
362 INLINE RefCountProxy<Base>::
363 operator Base &() {
364  return _base;
365 }
366 
367 /**
368  *
369  */
370 template<class Base>
371 INLINE RefCountProxy<Base>::
372 operator const Base &() const {
373  return _base;
374 }
375 
376 /**
377  *
378  */
379 template<class Base>
381 init_type() {
382  do_init_type(Base);
383  register_type(_type_handle,
384  "RefCountProxy<" + get_type_handle(Base).get_name() + ">",
385  get_type_handle(Base));
386 }
387 
388 
389 /**
390  *
391  */
392 template<class Base>
393 INLINE RefCountObj<Base>::
394 RefCountObj() {
395 }
396 
397 /**
398  *
399  */
400 template<class Base>
401 INLINE RefCountObj<Base>::
402 RefCountObj(const Base &copy) : Base(copy) {
403 }
404 
405 
406 /**
407  *
408  */
409 template<class Base>
411 init_type() {
412 #if defined(HAVE_RTTI) && !defined(__EDG__)
413  // If we have RTTI, we can determine the name of the base type.
414  std::string base_name = typeid(Base).name();
415 #else
416  std::string base_name = "unknown";
417 #endif
418 
419  TypeHandle base_type = register_dynamic_type(base_name);
420 
421  ReferenceCount::init_type();
422  _type_handle =
423  register_dynamic_type("RefCountObj<" + base_name + ">",
424  base_type, ReferenceCount::get_class_type());
425 }
ReferenceCount::has_weak_list
bool has_weak_list() const
Returns true if this particular ReferenceCount object has a WeakReferenceList created,...
Definition: referenceCount.I:244
RefCountProxy
A "proxy" to use to make a reference-countable object whenever the object cannot inherit from Referen...
Definition: referenceCount.h:120
AtomicAdjustDummyImpl::get
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
Definition: atomicAdjustDummyImpl.I:59
AtomicAdjustDummyImpl::compare_and_exchange
static Integer compare_and_exchange(Integer &mem, Integer old_value, Integer new_value)
Atomic compare and exchange.
Definition: atomicAdjustDummyImpl.I:93
ReferenceCount
A base class for all things that want to be reference-counted.
Definition: referenceCount.h:38
ReferenceCount::ref_if_nonzero
bool ref_if_nonzero() const
Atomically increases the reference count of this object if it is not zero.
Definition: referenceCount.I:306
register_type
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
Definition: register_type.I:22
ReferenceCount::get_weak_list
WeakReferenceList * get_weak_list() const
Returns the WeakReferenceList associated with this ReferenceCount object.
Definition: referenceCount.I:257
MemoryUsage::record_pointer
static void record_pointer(ReferenceCount *ptr)
Indicates that the given pointer has been recently allocated.
Definition: memoryUsage.I:32
ReferenceCount::weak_unref
void weak_unref()
Removes the indicated PointerToVoid as a weak reference to this object.
Definition: referenceCount.I:288
register_dynamic_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...
Definition: register_type.I:73
WeakReferenceList::ref
void ref() const
Increases the number of weak references.
Definition: weakReferenceList.I:20
RefCountObj
Another kind of proxy, similar to RefCountProxy.
Definition: referenceCount.h:146
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
ReferenceCount::weak_ref
WeakReferenceList * weak_ref()
Adds the indicated PointerToVoid as a weak reference to this object.
Definition: referenceCount.I:271
ReferenceCount::test_ref_count_integrity
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
Definition: referenceCount.I:197
AtomicAdjustDummyImpl::dec
static bool dec(Integer &var)
Atomically decrements the indicated variable and returns true if the new value is nonzero,...
Definition: atomicAdjustDummyImpl.I:27
AtomicAdjustDummyImpl::get_ptr
static Pointer get_ptr(const Pointer &var)
Atomically retrieves the snapshot value of the indicated variable.
Definition: atomicAdjustDummyImpl.I:81
unref_delete
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
Definition: referenceCount.I:329
WeakReferenceList
This is an object shared by all the weak pointers that point to the same ReferenceCount object.
Definition: weakReferenceList.h:29
ReferenceCount::ref
void ref() const
Explicitly increments the reference count.
Definition: referenceCount.I:151
MemoryUsage::remove_pointer
static void remove_pointer(ReferenceCount *ptr)
Indicates that the given pointer has been recently freed.
Definition: memoryUsage.I:90
ReferenceCount::local_object
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
Definition: referenceCount.I:229
ReferenceCount::unref
virtual bool unref() const
Explicitly decrements the reference count.
Definition: referenceCount.I:179
ReferenceCount::test_ref_count_nonzero
bool test_ref_count_nonzero() const
Does some easy checks to make sure that the reference count isn't zero, or completely bogus.
Definition: referenceCount.I:210
WeakReferenceList::unref
bool unref() const
Decreases the number of weak references.
Definition: weakReferenceList.I:32
ReferenceCount::get_ref_count
get_ref_count
Returns the current reference count.
Definition: referenceCount.h:53
AtomicAdjustDummyImpl::inc
static void inc(Integer &var)
Atomically increments the indicated variable.
Definition: atomicAdjustDummyImpl.I:18