This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Design summary: smart pointers in allocators


I think I've managed to a design for the alternative pointer support
which can work for varieties of 'smart pointers' as well as pointer
which represent alternative storage mechanisms.  (Phil, would
appreciate your feedback on this.)

The pointer used with the libstdc++ containers needs to implement the
interface defined in ext/pointer.h, and can use the test in
ext/nonstd_pointer/1.cc as confirmation.  This _Pointer_adapter
interface is similar to the interface of tr1::shared_ptr, extended to
include pointer arithmetic support, etc.  The pointer type doesn't
need to be _Pointer_adapter, just support the same set of operations.

Smart pointers pose a problem because of their behavior - they
generally can't handle the idea of pointing to any address that was
not dynamically allocated.  Thus pointing at array members (per
vector()) or pointing to members within a type (per list<>) poses a
problem.  Ultimately, the pointer has to become smart enough to deal
with that.  One approach involves the following:

a) Internally, the smart pointer has to track whether the address it
points to is something it should 'own' (i.e. a bit for tracking
ownership)
b)  operator=(T*) assumes the pointer will *not* own the memory being
assigned from that raw address.
c)  set(T* addr, bool owner) provides a more explicit set mechanism on
the pointer which allows the pointer to be told it should be
considered an owner (or joint owner) of the address being passed.  The
container will never call this method, but the allocator can...
d)  the allocator used with the smart pointer returns the smart
pointer type, and thus can call set() to assign that pointer properly
before returning it.  It always calls set(owner=true) to ensure that
the returned pointer manages the allocated memory.  Since the
allocator::allocate method is the point of origination of all
allocated memory used by the container, this means that all allocated
memory is initially paired with a smart pointer instance which knows
that it owns that memory.
e)  operator=(pointer<T> &rarg)  is written so that the lvalue takes
on the appropriate ownership from the rvalue, just as it would
normally.
f)  pointer arithmetic operations, like operator+=(size_t offset) sets
ownership=false, relieving the smart pointer of memory ownership, as
the address yielded may be within an allocated region.
g)  the allocator's deallocate() method takes a pointer by value, but
needs to ensure that all references to that address are cleared.  In
some cases, the 'cheat' of using a deallocate() method which takes the
pointer by reference allows the deallocation to occur by setting the
pointer to null.  As a safety this method can also ensure that the
pointer passed knows it is responsible for the address being
deallocated (that ownership = true)

I think the above may have some holes.  Possible.... but very ugly, I
admit.  I just haven't thought of anything cleaner.  The only other
alternatives that I've seen are:
a) don't support smart pointers, require that all memory management be
done by the allocator as intended by the standard.
b) redesign some containers (like vector) to avoid the pointer as
iterator idiom, and generally work to ensure that an
allocator::pointer only points to a heap allocated address, and so on.
 In my thinking, this is pushing too much responsibility onto the
containers, and involves far too much impact.
c) do the container changes with the assumption that
allocator::pointer is a smart pointer, and has to point to allocated
memory only.  With vector, this means some internal pointer use
allocator::pointer, and some remain normal T* to differentiate.
However, this design then breaks all cases of using alocator::pointer
for storage reasons (e.g. boost::interprocess::offset_pointer) and I'm
opposed to this.

Any opinions/thoughts welcome.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]