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::
197 test_ref_count_integrity() const {
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::
210 test_ref_count_nonzero() const {
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::
229 local_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  */
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  */
271 weak_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  */
287 INLINE void ReferenceCount::
288 weak_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  */
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  * 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  */
326 INLINE bool ReferenceCount::
327 unref_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  */
342 template<class RefCountType>
343 INLINE void
344 unref_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  */
360 template<class Base>
362 RefCountProxy() {
363 }
364 
365 /**
366  *
367  */
368 template<class Base>
370 RefCountProxy(const Base &copy) : _base(copy) {
371 }
372 
373 /**
374  *
375  */
376 template<class Base>
377 INLINE RefCountProxy<Base>::
378 operator Base &() {
379  return _base;
380 }
381 
382 /**
383  *
384  */
385 template<class Base>
386 INLINE RefCountProxy<Base>::
387 operator const Base &() const {
388  return _base;
389 }
390 
391 /**
392  *
393  */
394 template<class Base>
396 init_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  */
407 template<class Base>
408 INLINE RefCountObj<Base>::
409 RefCountObj() {
410 }
411 
412 /**
413  *
414  */
415 template<class Base>
416 INLINE RefCountObj<Base>::
417 RefCountObj(const Base &copy) : Base(copy) {
418 }
419 
420 
421 /**
422  *
423  */
424 template<class Base>
426 init_type() {
427 #if defined(HAVE_RTTI) && !defined(__EDG__)
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(),...
Definition: register_type.I:22
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