Boost logo

Boost :

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


> [snip]
>> Then what is the point of clone_allocator?
>>
>
> It does provide some room for customization. But it was deliberately kept
> very conservative, so we can extend it when we need to in light of user
> experience.

Isn't being able to create a clone using the parent containers' allocator a
practical necessity? The originals are made using that allocator - isn't it
natural to make clones using the same allocator?

> The current design uses static functions, and so there can be no stateful
>>> allocator.
>>>
>>> I thought a little about this, but have not come up with a solution.
>>> For example, how do we design an allocator that knows how to clone a
>>> class hierarchy?
>>
>>
Isn't this somewhat out of the scope of ptr_container?

> Only the class itself knows how to clone itself because it
>>> knows the exact type. OTOH, the classes in the class hieararchy doesn't
>>> know
>>> about the allocator.
>>>
>>> We might try a new way to clone objects by replacing
>>>
>>> virtual Base::clone() const = 0;
>>>
>>
>>
>> Isn't this what a copy constructor is for?
>>
>
> Types in object hierarchies usually don't expose their copy-constructor to
> avoid sliving.

But again, isn't this out of the scope? It's like the tail wagging the dog -
ptr_container shouldn't really be concerned with object hierarchies or not.
That's up to the user.

Surely, copy construction must be the best default way to make a clone? The
user can make their types noncopyable if needed.

> Furthermore, and more importantly, you loose the concrete type of the
> objects by having a container of pointers to the base class. Virtual
> functions are the most elegant way to ask the object
> for a copy of the right type.

Isn't this about ptr_container? We can't really have the specific usage of
OO hierarchies with containers of base pointers dictate the implementation
of an otherwise general system.

Introducing the idea of virtual methods and clone systems etc for
ptr_container seems like feature creep. Isn't all that another system
entirely? If the idea of clone_allocator was to give some customisation to
creating a clone of a value in a ptr_container, then surely it should use
the containers allocator, and it probably should use a copy constructor.

In light of which, it seems that clone_allocator itself isn't really
important or useful? If it really is there to try to do deep copies of
object hierarchies, that seems to me to be part of an altogether different
system and outside the scope of ptr_container. Otherwise, you should just
use the containers allocator to make the copy.

> [snip] This requires a public copy-constructor which we must not impose as
> a requirement, and even so it would not work because the concrete type is
> lost. (let's ignore that it is not exception-safe).

How will you make a clone without using a copy-constructor? Are you
suggesting something like is_convertible<base *, T*> then switching to a
virtual-method-based-scheme for clone??

I don't fully understand what you mean by "the concrete type is lost". Do
you mean in this sort of case?

struct Foo
{
    vector<Base *> bases;
    Foo(const Foo &other) { ... /* how to clone bases? */ }
};

If so, isn't that way out of the domain being addressed by ptr_container?

But I think now I see more clearly what you mean. You want to help with just
this case, is that right?

> But this raises another question I have: would we want all the objects to
> be allocated from the same allocator type using rebind<>, or would we like
> to use two different allocators.

I would argue for rebinding. Allocators are supposed to be rebound, I don't
think it is inelegant to do that. In any case, it still allows for the user
to provide an explicit specialising for a given type if needed, so they
don't lose control.

> Point being, can you just pass the container's allocator to the
>> clone_allocator?
>>
> Or, pass in a rebound allocator to allocate_clone; it doesn't really
> matter.
>
> I can, but I feel it is unanswered whether it should be the underlying
> container's allocator or simply the clone_allocator that somehow makes it's
> own allocations.

I don't understand why clone_allocator even needs to exist, let alone why it
shouldn't use the containers allocator if it must exist. If the container
allocator is good enough for values, it is good enough for clones.

I think I see that you wanted a way to help with the Foo case above, but
perhaps that really shouldn't be a part of ptr_container at all?

> And, as stated above, we also need to make sure that implementers of
> clone() get the allocator.

It seems that you added clone_allocator to help with cloning of
containers-of-base-pointers, but I can't see that working in general.
Attempting to do so is really reaching from system library space into
application space.

If needed, the user can make their own clone() system, and use it to
implement their own copy constructors, which would then be used by
allocator::construct in a ptr_container to make a clone and clone_allocator
then isn't even needed.

Perhaps the idea of cloning can be grafted away from ptr_container and made
into a seperate system. I can see why it's there, and the motivation, but if
it was to work properly it would be of general use and then not a part of
ptr_container anyway.

Regards,
Christian

PS. Perhaps just porting ptr_container to use boost::container rather than
std::container would solve Roberts problem?


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