Subject: Re: [boost] Stack-based vector container
From: Domagoj Saric (dsaritz_at_[hidden])
Date: 2011-01-30 11:55:23
"Thorsten Ottosen" <nesotto_at_[hidden]> wrote in message
> Den 26-01-2011 00:07, Domagoj Saric skrev:
>>>> Nice. It would be useful if it could do something similar for non-POD
>>>> types, i.e. it would take a functor in the constructor which it would
>>>> then 'walk' through the N entries and let it in-place construct them
>>>> avoid the usual default construction then assignment procedure)...
>>> well, you can just do that post-construction wise. No need for another
>> How would you do that in an exception-safe way (you need to correctly
>> 'roll-back'/unwind the construction if any of the constructors fail...)?
> Not that hard, just do some cleanup in the catch-clause.
That would be ugh-ly...
It would be akin to something like expecting users to manually predestruct a
std::string before assigning a new one to it...And wouldn't work
anyway...for example what would happen in the auto_buffer destructor in this
boost:.auto_buffer<std::string, N> buffer( n, boost::dont_initialize );
how would it know how many (if any) of the N std::strings it holds have been
constructed and need to be destroyed?
And, regardless of the above, if it is a common task why not provide it in
>>>>> Futhermore, you may use
>>>>> buffer.unchecked_push_back( x );
>>>>> to avoid code that checks for a full buffer and subsequent expansion.
>>>> AFAICT there is no ('unchecked') resize equivalent...
>>> unitialised_resize() ?
>> Is this also 'unchecked'?
> no, IIRC.
Then it is not an unchecked_push_back() equivalent...
>>>> ...Perhaps it would be a 'happier' solution to go with only one
>>>> option (policies/tags) or to replace both with a proxy 'unchecked'
>>>> class...So that when you want 'unchecked' access you call the proxy
>>>> getter and in effect get different semantics through an identical
>>>> interface...This would also 'play better' with Boost.Range and
>>> How? Range algorithms use iterators and not much else.
>>> boost::push_back( cont, range )
>> By calling/passing boost::push_back( cont.unchecked(), range ) or
>> boost::push_back( cont.uninitialised(), range ) ;)
>>> boost::push_back( cont, range )
>>> does not call cont.push_back(), and is the preferred way compared
>>> to using copy().
>> Yes, it calls insert() which still benefits from 'unchecked' resizing...
> so you want to save one if-statement in this rather expensive operation?
> If so, you can just use copy().
No, (as in the push_back case described by Christopher Jefferson) besides
the branching you save the _generation_ of a branch of code that will never
get executed and that will cause the whole function to be considered as
throwing by the compiler...
>>> For example, if
>>> the buffer does not need to be expanded, then it is likely the compiler
>>> can determine that the capacity_ member is not used.
>>> From my experience I'd consider that (highly) unlikely (if any resizing
>> function is called)...
> but why do you want to call a resizing operation? I assume in this case
> that the buffer is fixed after construction.
It isn't/need not be, the first container type from the list posted in
response to Nevin Liber (resizable with fixed-capacity) can be resized
without need for 'capacity' or exceptions...
Plus, the constructor can also be considered a 'resizing' function (it sets
the capacity to an initial value)...
>>> nor do I see how one can avoid it when we need to go for the heap in
>>> certain cases.
>> Exactly, that's why I asked for a no-heap policy...however now I think
>> its better to model each of the different 'variants' with a separate
> Seems like a big step. Let's see what the assembly analysis comes up with.
> In the mean time it would help if you could write some small
> use cases explaining which functions you want to call in the different
> scenarios (this would also make the discussion more concrete).
I honestly don't see why is this a big step...as I don't see the need for
actual assembly analysis - the four vector-like container versions I
proposed are all rather simple concepts/classes (except of course for the
second one, the equivalent of your auto_buffer) and thus relatively simple
to implement (ad 'big step') with relatively predictable
'footprint'/generated code (ad 'analysis') and rather obvious use cases
(e.g. a "fixed size/non-resizable dynamically stack allocated 'vector'" is
obviously to be used in cases where the size of the container is known at
runtime but known not to be too large not to fit on the stack and that there
will be no need for resizing)...
-- "What Huxley teaches is that in the age of advanced technology, spiritual devastation is more likely to come from an enemy with a smiling face than from one whose countenance exudes suspicion and hate." Neil Postman