|
Boost : |
From: David Abrahams (dave_at_[hidden])
Date: 2003-09-02 10:22:25
Gregory Colvin <gregory.colvin_at_[hidden]> writes:
>> I think part of my point was that *nobody* needs what they offer, if
>> you include construct/destroy.
>
> Or rather that some implementations have failed to use what they
> offer, and our standard unfortunately doesn't insist that they do.
It's not unfortunate if it adds nothing, which is what I believe.
> Another reason construct is needed is that Allocator::pointer might
> be a proxy, with operator* and operator-> but not necessarily a
> conversion to void* or even T*.
Doesn't matter; you can always get the address of an object. See
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-closed.html#390
>> In fact, construct requires undefined behavior for non-POD T
>> because you can't copy its T* argument which points into raw
>> storage.
>
> I don't understand what you mean by this. Are you claiming that
> it is undefined to copy just a pointer to raw storage?
Unless the pointer has the right type, yes.
> If so, then how is placement new not undefined?
It uses a void*, as shown in your code snippet below.
> The standard says:
>
> a.construct(p,t)
> Effect: new((void*)p) T(t)
>
>> I think I would rather see a MPL lambda expression or metafunction
>> class interface for allocator type parameters. It makes little sense
>> for the allocator's user to be choosing its value_type.
>>
>> Something like:
>>
>> some_allocator<_1>
>>
>> or
>>
>> struct select_allocator
>> {
>> template <class T>
>> struct apply
>> {
>> typedef some_allocator<T> type;
>> };
>> };
>>
>> with some_allocator's interface being like what's required for
>> std::allocator but not including misplaced interface bits such as
>> address/construct/destroy, and possibly max_size -- these can be added
>> by a std::allocator facade wrapper if neccessary.
>>
>> I'm not sure we need a simple version and a complicated version.
>
> I'm not clear how you intend the above to be used, or what you
> intend it to be a replacement for.
I intend it to be the sort of type parameter that gets passed to our
objects which need custom allocation in place of a standard allocator.
It's ridiculous, IMO, to pass allocator<T> to a node-based container
which is *never* going to allocate a T object. The container itself
should decide which type the allocator template gets instantiated on,
via:
mpl::apply<mpl::lambda<S>, Node>::type
[
this is approximately the same as:
S::template apply<U>::type == some_allocator<U>
except that it works when S is the lambda expression
some_allocator<_1> as well as when it's the select_allocator
metafunction class below it.
]
What the rebind requirement in the allocator means for pool
allocation, for example, is that a pool_allocator<T> object must
either be stateless (in which case allocator inequality is
meaningless) or effectively be able to allocate blocks of *any* size
and alignment, rather than just as appropriate for T. It's a
conceptual mess.
-- Dave Abrahams Boost Consulting www.boost-consulting.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk