x::ref
s and x::ptr
s generally take the chore out of keeping track of
heap-allocated objects, and destroying them when they're no longer needed.
When the last reference to the object goes away, that's it. For this to
work, it's important not to create circular references.
The simplest circular reference is an x::ref
or an x::ptr
in one object pointing to a second object, and an x::ref
or an x::ptr
in the second object pointing to the first one. This is true for a
circular reference of any size or structure, a sequence of any lengths
of x::ref
's; and x::ptr
s eventually leading back to the starting point.
A circular reference prevents the
objects from getting destroyed, when no other references to the objects
in a circular reference remain.
Weak pointers do not count, and won't create circular references, but there has to be a strong reference to an object somewhere, for it to exist. LibCXX's documentation often specifies when a class or an object instance holds a strong reference to another object, and under what circumstances. This should be considered when designing a class hierarchy, and avoiding creation of circular references and memory leaks.
The internal usage of x::ref
's and x::ptr
's is very widespread, and their
existence gets explicitly noted, in this documentation, only when it is
counterintuitive, or not obvious. For destructor callbacks and mcguffins:
A mcguffin holds a strong reference on all callbacks that were
addOnDestroy
()ed.
Those strong references naturally go out of scope, and get destroyed,
as part of the mcguffin's destruction (and invocation of all of its
addOnDestroy
()ed callbacks).
An
x::ondestroy
indirectly holds a strong reference to the mcguffin's destructor
callback. x::ondestroy
does not actually
hold a strong reference of its own.
What happens is that x::ondestroy
's
cancel
() (whether invoked explicitly or
implicitly) releases the mcguffin's strong reference on its callback,
if it's not yet invoked. If it was already invoked, as part of the
mcguffin's destruction, x::ondestroy
has
no further impact.
onAnyDestroyed
()
creates a strong reference from every mcguffin, defined by the
input sequence, to onAnyDestroyed
()'d
destructor callback. Those strong references go out of scope when
one of those mcguffins goes out of scope, gets destroyed, and results
in the contracted-for invocation of
destroyed
().