This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: Design summary: smart pointers in allocators
"Bob Walters" <bob.s.walters@gmail.com> wrote in message
3d6744d10808261529o33724bees4071c6e713c7f816@mail.gmail.com">news:3d6744d10808261529o33724bees4071c6e713c7f816@mail.gmail.com...
>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.)
[...]
I will review the classes in my spare time but the following caught my
attention.
> 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.
I think a redesign will be needed inside the containers because smart
pointer support is inevitable. Fortunately I don't think this is a big
problem outside the clear(node *) and insert(node *) operations.
I think there is a solution towards the approaches we are studying. The
problem with having deallocate(smart_ptr &) passing its argument as a
reference is that this will break an attempt to virtualize allocators:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2387.pdf
There are different solutions we can take which would consist of
virtualizing the functions returning allocated block, such as (in list<>):
- virtual _List_node<_Tp>* _M_get_node()
- virtual void _M_put_node(_List_node<_Tp>* __p)
But I was considering yet another approach which would have to be well
tested in terms of usability because it may involve run-time issues. The
idea would be to add an implicit convertion function to type "void *" to the
smart pointer class. But this operator woudl require giving away its
ownership of the pointer and returning 0 (nullptr) if the reference count
isn't yet down to zero:
template <typename T>
class smart_ptr
{
...
operator bool () ...
operator const void * ()
{
return -- _M_count ? 0 : _M_p;
}
};
At that point the allocator wouldn't even have to worry about the type of
pointer being passed in because an implicit convertion will occur before the
function is called:
template <typename T>
class allocator
{
...
void deallocate(const void * __p)
{
if (__p) ...
}
};
This would be very clean but I think supporting smart pointer inside the
allocator will be safer because the allocator is already aware it's using
them (typedef smart_ptr<T> pointer).
-Phil