Boost logo

Boost :

Subject: Re: [boost] [ptr_container] ptr_vector across DLL boundaries
From: Christian Schladetsch (christian.schladetsch_at_[hidden])
Date: 2009-06-26 21:09:42


Hi Thorsten,

On Sat, Jun 27, 2009 at 11:48 AM, Thorsten Ottosen <
thorsten.ottosen_at_[hidden]> wrote:

> Christian Schladetsch skrev:
>
> PS. Perhaps just porting ptr_container to use boost::container rather than
>>>
>>>> std::container would solve Roberts problem?
>>>>
>>>> No. He needs to "install" his own new/delete with the container.
>>>
>>
>> Isn't this called a stateful allocator? Which boost::container supports?
>>
>
> Hm. Is it? So construct() and destroy() would act as custom
> allocator/deleter?

No, the custom allocator would act as a custom allocator. Obviously I don't
follow this. If you want to "install" custom new and delete into a
container, isn't this best achieved by using a stateful allocator? If so, it
seems the best want to support stateful allocators is to base ptr_container
on boost::interprocess::containers (hopefully soon to be boost::containers)
rather than std::containers.

It seemed to me that Robert needed stateful allocators for ptr_containers.
You said he didn't. But now you made clone_allocator stateful, but left the
normal allocator stateless. I'm confused.

> Anyway, let's say that all allocation is done with the supplied allocator
> via rebind<>. This is what you require to use ptr_container with monotonic
> allocators, right?

No. Monotonic works well with either stateless or stateful allocators.

The problem was that I could not implement a sane clone_allocator for
ptr_container, and I didn't know how anyone else would either.

Now that you made clone_allocator stateful, I still can't pass it the
containers allocator at constructon time.

Why not make the parent allocator stateful, and pass it to a static clone
method in a stateless clone_allocator? Doesn't that make more sense and
solve more problems?

> But how do you get objects into the ptr_container in the first place?

In a perfect world, I would pass a pointer to be added to a container of
pointers:

   ptr_container<T> c;
   c.push_back(new T(..args..));

Then use value semantics of type T and not T * on the contained elements.
But I realise that isn't how it works.

> Do you intend users to write
>
> container c;
> c.push_back( c.get_allocator().construct(
> c.get_allocator().allocate(sizeof(T)) );

No - why would they? That is what the container does internally. I am sure
you are making a good point here, I just can't see it.

All I need to make ptr_container work for me is to give the clone_allocator
access to the parent container's allocator - preferably just by passing it
to clone_allocator::clone rather than making it stateful. It makes sense to
me that clones should be made using the parent container's own allocator,
which it used to make the originals with in the first place.

But then when you think that through, it seems that clone_allocator itself
is a practically useless appendage.

Unless you want clones to be made using a stateful sort-of allocator that
does not model std::allocator, is different to the parent containers
allocator, and you want to ensure that clones must be made using a different
allocator to the parent container allocator.

The obvious question then is: why you would want to do that, and how it is
useful in any way?

What would be useful is if ptr_container supported stateful v2 allocators
based on boost::interprocess::containers, rather than stateless v1
allocators based on std::containers.

Is this how you expect it to work for Robert and others?:

   struct my_stateful_custom_clone_allocator
   {
        ...state here, including some way to store a general allocator ...
       template <class U>
       U *clone(U const &X)
       {
            ...use the general allocator in this->state to make the clone of
X...
       }
   };

    ptr_container<T, my_stateful_custom_clone_allocator,
my_custom_normal_allocator<T> > cont;
    my_custom_clone_allocator &alloc = cont.get_clone_allocator();
    alloc.parent_allocator = cont.get_allocator();
    alloc.... = ...;

rather than:

    struct my_stateless_custom_clone_allocator
    {
       template <class U, class Alloc>
       U *clone(U const &X, Alloc &alloc)
       {
            // use alloc to make a clone of X
       }
    };
    ptr_container<T, my_stateless_custom_clone_allocator,
my_custom_normal_allocator<T> > cont;

Having the users needing to dig into an otherwise private piece of machinery
within the container itself - especially after it is created - seems really
ugly. Isn't it better to do all the setup in the type and ctor for a
ptr_container?

I'm obivously missing something. Do you have any use-cases or examples that
use a custom clone allocator with a ptr_container? Either stateless or
stateful?

I still think that the entire issue of cloning from base types is best put
into a seperate, orthogonal system outside of ptr_container. However, I
understand that you wanted to support it as a specific case for
ptr_containers in the context of OO hierarchies. I also understand that you
don't want to use copy-constructors to make a copy; there is no need to
repeat either sentiment.

And how do you pass constructor arguments to construct?

Forwarding construction arguments is a general problem that is not limited
to the std::allocator concept.

> -Thorsten
>

Best,
Christian


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