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 }
static Pointer get_ptr(const Pointer &var)
Atomically retrieves the snapshot value of the indicated variable.
bool test_ref_count_nonzero() const
Does some easy checks to make sure that the reference count isn't zero, or completely bogus.
void ref() const
Increases the number of weak references.
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
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
This is an object shared by all the weak pointers that point to the same ReferenceCount object.
static void inc(Integer &var)
Atomically increments the indicated variable.
static bool dec(Integer &var)
Atomically decrements the indicated variable and returns true if the new value is nonzero,...
bool has_weak_list() const
Returns true if this particular ReferenceCount object has a WeakReferenceList created,...
void weak_unref()
Removes the indicated PointerToVoid as a weak reference to this object.
static void remove_pointer(ReferenceCount *ptr)
Indicates that the given pointer has been recently freed.
Definition: memoryUsage.I:90
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
void ref() const
Explicitly increments the reference count.
WeakReferenceList * weak_ref()
Adds the indicated PointerToVoid as a weak reference to this object.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
A base class for all things that want to be reference-counted.
bool ref_if_nonzero() const
Atomically increases the reference count of this object if it is not zero.
Another kind of proxy, similar to RefCountProxy.
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
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:69
A "proxy" to use to make a reference-countable object whenever the object cannot inherit from Referen...
static void record_pointer(ReferenceCount *ptr)
Indicates that the given pointer has been recently allocated.
Definition: memoryUsage.I:32
virtual bool unref() const
Explicitly decrements the reference count.
static Integer compare_and_exchange(Integer &mem, Integer old_value, Integer new_value)
Atomic compare and exchange.
WeakReferenceList * get_weak_list() const
Returns the WeakReferenceList associated with this ReferenceCount object.
bool unref() const
Decreases the number of weak references.