|
Boost : |
From: John Maddock (John_Maddock_at_[hidden])
Date: 2000-05-16 06:36:58
Steve,
>As Nathan Myers has pointed out, the allocator requirements don't quite
line
up with what the containers require. That's why there's two allocators:
pool_allocator, which is an instance-based allocator, satisfying Allocator
requirements; and std_pool_allocator, which is not instance-based, and
allows usage with std:: supplied containers [20.1.5/4]. std_pool_allocator
is the only allocator that is officially permitted for use with std::
containers (and it does garbage cleanup only at the end of the program).<
OK got it, in that case I think I would dump the instance based allocator,
unless you have a specific use for it.
>I took pains to avoid this kind of problem -- that's where the extra
template parameter on the allocators comes from. The last parameter is the
*original* type of the allocator; if the allocator is rebound to another
type, it *won't* use the pool. But if it is rebound *again*, back to the
original type, then it will use the pool again. Kind of convoluted, but it
works. :)<
You might be able to strengthen things a little here - for example
std::list<int> is an obvious candidate for a pool based allocator, as are
the set and map classes, however the allocators they use are not the ones
supplied in the template parameter - but a rebound copy. That rebound copy
should also be pool based, albeit using a different pool from the original,
the "trick" is to ensure that the underlying pool only gets constructed if
allocate is actually called (so that there is no penalty in constructing an
allocator unless it is actually used to allocate something).
>As pointed out in my response to (3), above, the pool allocators are
useless
when applied to containers. I'm thinking of having the "standard"
allocator
not depend on pool<T> anymore, but rather on sized_pool<N>, and dropping
the
instance-based allocator completely. The allocator will lose its "garbage
collection" properties, but I don't really see that as necessary for
allocators, anyway. Then the allocator can always allocate from
sized_pool's, even if rebound.
That will still leave pool<T>, for those who want to have garbage
collection
semantics.<
Yep that sounds better.
>In the mean time: I will look at thread safety issues, and could you,
John,
explicitly state your concerns with static data members? (I'm a little
slow
sometimes... :)<
When is the static data member constructed? If I declare:
std::list<int> i_list;
as a global, or in some startup code, is the static data member of the
allocator constructed before or after i_list? It all depends upon how the
compiler arranges things, the same arguments apply to program shutdown
code: conceivably the i_list may be calling deallocate after its allocators
static data has already been destroyed. The only solution that I know of
is to create a "reference counted singleton": objects using the singleton
increment its reference count while using it, and decrement it when they've
finished (the allocators constructor/destructor would be a good place for
this). This topic comes up a lot on comp.lang.c++.moderated, and in
various journals - I don't know of any solution that everyone would
consider ideal though.
- John
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk