Boost logo

Boost :

Subject: Re: [boost] Request for help in porting colony to boost from experienced container boost dev
From: Glen Fernandes (glen.fernandes_at_[hidden])
Date: 2015-08-25 06:55:58


On Tue, Aug 25, 2015, [Matt] wrote:
>> Regarding your use of allocators in your implementation:
>> a. Support the C++ allocator model
>> 1. Either use a.allocate(size) or allocator_traits<A>::allocate(a,
>> size, hint) if you want to supply a hint, but don't bother calling
>> a.allocate(size, 0) - you alienate anyone who writes a C++11 allocator
>> that may not provide an allocate(size, hint) member.
>
> Right - this might be something that has to change for the boost submission,
> the original is designed to work with both C++0x and C++11, and the hints
> made a substantial difference to speed with std::allocator.

Hints are fine. But use them with std::allocator_traits::allocate or
boost::allocator_traits::allocate.

>> 2. Use allocator_traits<A>::construct(a, ...) and
>> allocator_traits<A>::destroy(a) instead of a.construct(...) and
>> a.destroy(...)
>
> Why, and is there a C++0x-friendly way of doing the same thing?

std::allocator_traits is the C++11 and above way of doing things.

>> 3. Use allocator_traits<A> to obtain the type members (pointer, rebind,
>> etc.)
>> (You could use boost::allocator_traits if you want to support pre-C++11)
>
> What is the advantage of doing this?

The motivation for using std::allocator_traits in all of these 3
points (a.1-a.3) is to support the C++11 allocator model. The C++
standard library does this. Most Boost libraries also do this.

>> b. Use a compressed_pair<> or the EBCO to reduce the storage for when
>> stateless allocators are supplied (i.e. instead of the 1 + 1 bytes
>> that would be used for the empty objects).
>
> Empty base optimization is not something I understand at this point. I've
> read a bit about it but I am not sure in which particular area of the colony
> it would make a difference in?

When someone supplies a stateless allocator, like std::allocator<T>,
the sizeof(allocator) is still 1 and thus the size of your container
object is increased by 1 when it doesn't need to be. The EBCO (or
compressed_pair) can be used here to make sure that empty allocators
do not add the extra +1 byte to your container object storage. This is
also a commonly used technique in C++ standard library
implementations, as well as in many Boost libraries that support
custom allocators and custom deleters.

>> c. Support element_type's whose constructor might throw: Do you catch,
>> accordingly destroy any constructed elements, deallocate any allocated
>> elements, before rethrowing?
>
> I guess that makes sense in the limited scenario where memory is full.

No. We're not talking about allocate() throwing (which could happen
because of memory being full, or just some constraints a particular
generic custom allocator may have that are violated). We're talking
about construct() throwing. Both C++ standard library containers, like
std:;vector<T>, and containers in Boost libraries, must acknowledge
the fact that constructing a T object (i.e. ::new(p) T(...) or
std::allocator_traits<A_>::construct(a_, p, ...) may throw - and if
you're constructing N objects in a loop, and the J-th construction
throws, you need to destroy the (J-1)-th down to 0-th constructed
elements before you deallocate the storage.

> My general feeling is more in line with Mike Acton's in that if something
> throws, you've got a problem anyway - peaceably unrolling isn't really
> helping anyone.

You're actually misunderstanding Mike completely, and out of context.
Writing generic code around T (value type) or A (allocator type)
requires that you handle things like this. As I mentioned, the C++
standard library containers do this. So do Boost library containers.
If you do things like both allocate and construct, and construction
throws, and the user of your library has no way to deallocate what
you've allocated, it completely alienates them using your container in
any of their generic code where they support T types whose
constructors can throw, etc.

Best,
Glen


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