Boost logo

Boost :

Subject: Re: [boost] [review] The review of Boost.DoubleEnded starts today: September 21 - September 30
From: Tim Song (t.canens.cpp_at_[hidden])
Date: 2017-09-26 19:36:00

On Tue, Sep 26, 2017 at 1:14 PM, Thorsten Ottosen via Boost
<boost_at_[hidden]> wrote:
> The missing _emplace functions is surely an oversight.

Fair enough.

> I the thread with Zach's review I tried to view this from a more
> philosophical viewpoint. What is safe and unsafe is highly subjective (and
> as I wrote in the other thread, it is a mistake to use the word "unsafe" in
> the function name").
> But C++ is not memory safe like Java or C#, and there are tons of
> preconditions in C++ code that are only checked with debug assertions. Yet I
> don't think in general that C++ programs have more bugs than Java or C#
> programs. Take a look at various Boost libraries and they offer plenty of
> opportunity to shoot yourself in the foot. But we use them anyway because
> they offer functionality and performance that cannot be found in any other
> way. Said differently: all the alternatives are worse. As just one example:
> I can use Boost.Intrusive and it is surely harder to use than normal
> containers, but the performance is awesome and compared with all the
> hand-rolled, ad hoc alternatives, it's vastly superior.
> So it's easy to say something is hard and unsafe to use. But what about the
> alternative?

The problem is that the new hard/unsafe parts isn't justified by any
hard performance numbers. We are talking about adding functions that
make it more likely for users to do things wrong, possibly in a manner
that's completely well-defined but massively inefficient
(inappropriate reserves). The benefit from it is skipping a branch
that the predictor probably gets right most of the time. On its face,
this doesn't appear to me to be a substantial enough benefit to
justify the cost. It is of course quite possible that I'm
underestimating the benefit, but if so I'd like to see actual numbers
proving it.

>> What's the motivating use case for the unsafe_uninitialized functions
>> that can't handled by a non-invariant-violating design like
>> default_init? The sole example in the documentation is a
>> devector<char> whose content will be filled by recv later, which can
>> be handled equally well.
> Can you elaborate on what this design is exactly? Thanks.

The same design used in boost::container. You take a tag type that
indicates that the elements should be default-initialized rather than
value-initialized. For trivially default constructible types, this
means that no initialization is actually performed.

Of course if the type isn't trivially default constructible, it would
still call the constructor. The question is: how often do such cases
actually arise?

>> I'm somewhat surprised that dropping the move_if_noexcept/strong
>> exception safety dance doesn't seem to have been considered for a
>> container that's supposed to be performance-oriented.
> For which container operation are you thinking about?

Anything that reallocates, really. Basically, unconditionally move
during reallocation instead of move_if_noexcept, and if the move
throws you only get basic exception safety.

>> The default growth policy is:
>>> static size_type new_capacity(size_type capacity);
>>> Returns: 4 times the old capacity or 16 if it's 0.
>> Why those numbers? Were they arbitrarily chosen or based on some sort
>> of benchmark? If so, what?
> In this connection,
> may be relevant. It argues for a 1.5 growth factor.

Indeed. I've seen 1.5. I've seen 2. 4, on the other hand, I haven't
seen before, so I'm curious if there's anything behind that choice.

Boost list run by bdawes at, gregod at, cpdaniel at, john at