Boost logo

Boost :

From: scleary_at_[hidden]
Date: 2000-05-15 09:53:57


> 1) The pools destructor enumerates through all the elements and deletes
> those that haven't been deleted - potentially this could be quite an
> expensive operation - it's also breaks std::allocators requirements (see
> below).

As Dave Abrahams pointed out, this is intended behaviour. However, for your
convenience (and mine), pool<T> is built on sized_pool<N>, which handles
everything necessary for non-type-dependent memory pools (without destructor
cleanup).

I don't *think* it breaks the allocator requirements. If your're worried
that elements might be deleted by pool<T> before the container's done with
them, see below.

> 2) The static allocator version (std_pool_allocator I think) uses a static
> member for the pool - this efectively prevents this allocator from being
> used in program startup/exit code - as would happen if you declare a
global
> variable using this allocator for example, the normal solution for this
> situation is to use a singleton: boost::singleton anyone?

I'm not sure what the problem is here. The order of initialization?

> 3) The allocator requirements permit containers to allocate memory with
one
> allocator and free with another un-related allocator (think of
list::splice
> for example), in fact the lifetime of allocated memory can be independent
> of that of the allocator, I think this kind of usage would crash your
> allocators (due in part to #1)?

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).

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. :)

Because of this, pool allocators are (as they currently stand) simply not
usable. See below for my plans to change this.

> 4) The allocators aren't thread safe - this is very important from my
point
> of view, but opens up a whole can of worms you may not want to get into.

I can't believe I overlooked this!

I'll probably just look at the way others have done it in the smart pointers
(I'm assuming we used some sort of wrapper around OS-specific mutexes), and
do it the same way.

> 5) It would be nice to see some performance comparisons between the pooled
> allocators and std::allocator/operator new

Yes, but for as many compilers/stdlib vendors as possible. Memory
allocation strategies may vary widely. Maybe we could provide a "benchmark"
program.

--- Future Direction ---

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.

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... :)

        -Steve


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