|
Boost : |
From: Gregory Colvin (gregory.colvin_at_[hidden])
Date: 2003-08-30 22:36:06
On Saturday, Aug 30, 2003, at 20:13 America/Denver, David Abrahams
wrote:
>> ...
>> Indeed -- they are overkill for many purposes. The user allocator
>> interface in Boost pool is more appropriate when all you need to
>> indicate is how to malloc and free
>
> What else do allocators really do? If "the user allocator in Boost
> pool is more appropriate" for those purposes, maybe that's what we
> ought to be parameterizing our class templates on.
Maybe so. It depends on whether the class can take good advantage
of what the Standard Allocator provides that the Boost UserAllocator
doesn't, and vice versa.
> ...
>>> (**) Here's another example: you have to tell allocators how much
>>> memory you're deallocating. What's that all about?
>>
>> Efficiency. The container already knows the size, so there is no need
>> for allocate() to squirrel it away for later.
>
> I thought of that, but I also seem to remember that allocate was
> always calling operator new in real implementations (which of course,
> squirreled away the size). It's been a long time since I looked
> though.
A high quality allocator (like boost::pool_alloc) calls new or malloc or
some system routine or whatever for big chunks, and splits them up very
efficiently into smaller bites.
>> Similarly, shared_ptr knows the size of the counts it allocates, and
>> I suspect there are potentially many other such cases. But I don't
>> know about function<>.
>
> I don't think it falls into that category. Neither does shared_ptr
> when you use custom deleters, AFAICT.
shared_ptr currently uses std::allocator to allocate counts
regardless.
>> But indeed allocate/construct/deallocate/destroy is more work than
> ^^^^^^^^^ ^^^^^^^
> Oyeah. These two absolutely don't belong in allocator, period. Do
> any implementations even use them? Allocators exist to provide a
> point of customization for users, but you cannot/should not customize
> these.
Conforming containers had better use them. And once you are down in
the coal mine customizing what a pointer is, I'm not sure you won't
need to customize how to construct and destroy. But not many of us
ever need to go down in that mine.
>> new/delete, so the potential performance win of using an allocator is
>> often not worth the extra coding.
>
> Using allocator is even more work than allocating raw memory with
> malloc and doing placement new and explicit destruction, then freeing
> the raw memory. That's my biggest complaint.
It's new/delete
T* p = new T();
...
delete p;
versus malloc/free
T* p = (T*)malloc(sizeof T);
new(p) T();
...
p->~T();
free(p);
versus Boost UserAllocator
T* p = (T*)user_allocator::malloc(sizeof T);
new(p) T();
...
p->~T();
user_allocator::free(p);
versus standard Allocator
Allocator::pointer p = allocator.allocate(sizeof T);
allocator.construct(p,T());
...
allocator.destroy(p);
allocator.deallocate(sizeof T);
Unless you are writing a lot of allocations none of them seem all that
painful, so I think it's more whether you need:
* fast allocation of lots of small objects of few different sizes
* not (very) customizable
-- use boost::pool_allocator or std::allocator directly
* customizable
-- use standard Allocator requirements, or a subset thereof
* few objects or large objects or many different sizes or cannot
track
size or performance not critical or ...
* not (very) customizable
-- use new/delete
* customizable
-- use boost UserAllocator requirements
And for customizability we have at least:
* replaceable global new/delete
* class-specific new/delete
* allocator (Standard, Boost, or ...)
* as class template parameter
* as function template parameter
...
...
"Ya pays yer money and ya takes yer choice."
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk