
[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?