Boost logo

Boost :

From: Andy Glew (glew_at_[hidden])
Date: 1999-07-26 18:53:12


>http://www.octopull.demon.co.uk/arglib/uncounted_ptr.html

Great minds think alike. I was not aware of Java's weak references,
but had concluded that there was a need for something like this,
and meant to push live_ptrs in this direction.
I don't consider them a substitute for garbage collection, however.

Note that live_ptrs (pointers that get nulled on deallocation of the
pointee, uncounted pointers, weak references) require a registration
system that points back to the pointers, while keepalive_ptrs
(reference counted pointers, strong references) can be implemented without a
registry.

Note that the term "keepalive_ptr" is more general than
"reference counted pointer", since the concepts of live_ptr
and keepalive_ptr could also be implemented with garbage
collection rather than reference counting.

Note that, if a registry is used for keepalive_ptr, that it eliminates
the need for a reference count. List/full/empty is the predicate
for deallocation. Some variant of this may actually lead to more
efficient parallel code: rather than mutexing a single reference count,
lacking a hardware parallel atomic fetch-and-increment,
parallel insert/delete on a parallel registry datastructure may be used.
However, the same efficiency is obtained by using multiple reference
counts hashed or randomized to reduce contention on mutex.

In general, you would only want to use a pointer registry for keepalive_ptrs
if there was some other reason that you wanted to reverse the pointers.

Which brings me to my main issue:

The registry for live_ptr is easily implemented as a list or map of (back) pointers
to live_ptrs. This allows you to go and zero these pointers on deallocation,
but not much else.

More generally, you want to obtain a back pointer to the object that contains
the live_ptr. E.g.

        template<class T> class regd_ptr {...};
        template<class T> class regd_ptee {
                typedef map< T* > registry_t;
                registry_t ptr_registry;
                ...
        }

        template<class T> class live_ptr {...};
        template<class T> class live_ptee {
                typedef map< live_ptr<T>* > registry_t;
                registry_t ptr_registry;
                ...
        }

        class foo_t {
                ....
                regd_ptr<bar> bar_rp;
                live_ptr<bar> bar_lp
                ...
        } Foo_Instance;

        class bar_t : public regd_ptee<T>, live_ptee<T> {
                ...
        } Bar_Instance;
                
What you want in general is for the backpointers for general pointer
registries to point to the object that encloses their reference. Or, equivalently,
you want to be able to obtain that object by walking up the class nestings.

Ideally, you would like a statement like

        Foo_Instance.bar_rp = &Bar_Instance;

to establish that. But, whereas the live pointer version

        Foo_Instance.bar_lp = &Bar_Instance;

has all of the information it needs, the regd_ptr version doesn't.

In LISP, Smalltalk or Java it is possible to walk the symbol or object tables
in order to figure out which objects enclose any particular reference.

In C++ it appears to be much harder. You can save that offset away during
construction of the enclosing object.

Or, you can do something like

        set_ptr_with_registered_backptr( Foo_Instance, bar_rp, Bar_Instance )

which extends to the 1:1 reversible structure

        set_ptr_with_backptr( Foo_Instance, bar_rp, Bar_Instance, foo_rp )

but I consider all of the above ugly.

Q: is there any syntactically pleasant way of acheiving the desired effect?

{Hmmm.... I suppose that yet another wrapper type could be defined
for which operator-> produces a tuple of (Object,Field) that can be passed around
wherever needed. Has anyone coded that up?}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk