Boost logo

Boost :

Subject: Re: [boost] Interest in StaticVector - fixed capacity vector
From: Dave Abrahams (dave_at_[hidden])
Date: 2011-10-15 09:27:34


on Fri Oct 14 2011, Christian Holmquist <c.holmquist-AT-gmail.com> wrote:

> On 14 October 2011 16:07, Peter Dimov <pdimov_at_[hidden]> wrote:
>
>> Christian Holmquist wrote:
>>
>>> On 14 October 2011 12:55, Dave Abrahams <dave_at_[hidden]> wrote:
>>> > Is throwing an exception going to turn an incorrect program into a
>>> > correct one?
>>>
>>> I'm probably completely misunderstanding your point of view, or rather,
>>> what is your point of view?
>>>
>>
>> He's saying that if a program does a push_back when the capacity has been
>> reached, this program has a logic error, and throwing an exception will not
>> make the error go away.
>
> To me this is like saying that if any exception is thrown, the program has a
> logic error.

I don't see how anyone could draw that conclusion.

> It's not very helpful though. All code which does not deal with global
> OS data (such as the heap, files, etc) can be written as no throw,
> if enough details are exposed for the user.

Only by reporting the error another way. There's no way for a user to
check beforehand that there is going to be enough memory to complete any
given job requiring a dynamic allocation. And if you consider memory
"global OS data" then yes, the code that doesn't need to allocate
resources and can always complete successfully in the absence of
erroneous usage should be no-throw.

On the other hand, /this/ problem is in the user's power to prevent, and
I assert that in the vast majority of imaginable use cases the user will
have tried to get prevention right (i.e. will have tried to choose the
length to be sure everything fits).

> But I want code to throw so that I don't need to worry and check all
> details everywhere.

If your code detects a programming error, you need to worry. Yes, it's
true that once you say "I'm going to throw under these conditions" it's
no longer certain that it's a programming error, but I assert that in
this case it remains highly likely. But then the library is no longer
allowed to treat it as an error and helpfully do the most appropriate
thing for debugging purposes; it has to throw an exception, because it
promised to.

What's your program's response to that exception? In many programs when
there's an exception it gets logged and it tries again later. By the
time you catch the exception far from the call site, you no longer know
for sure whether it was a programmer error or not, so you don't really
have a choice. This is how bugs stay hidden.

We mostly have a consistent practice in the C++ standard library and in
Boost that we respond to programming errors with undefined behavior and
*not* with a documented defined behavior, which has the effect of making
it harder to detect bugs. [Now I'm proposing broadening that practice in
Boost to help avoid undefined behavior.]

> How much juggling would I need to do to parse a comma separated text of
> integers into a static_vector?
> static_vector<int, 4> v;
> spirit::parse("1, 2, 3, 4, 5", int_ % ',', space, v); // undefined
> behaviour???

Nobody likes "unefined behaviour???" But please allow me to replace
that comment with:

     "// throws an exception???"

It's just not the most appropriate response. For those who want
checking, dropping into the debugger or dumping core or logging and
terminating would be better, and those who don't will be annoyed to pay
for unneeded checks when their code is correct. Why should the library
be locked into providing what is almost always a suboptimal response?

> Sure, the above can be seen as having a 'logic error' because the grammar
> says parse N but the capacity can only handle N < 5.

Um, yeah, and because you wrote the existence of 5 items right into the
program at the call site. In most cases there's a better chance that
it's not a logic error. If this isn't a logic error, it's a perverse
way of writing "throw capacity_exceeded()" for which the programmer
should receive fifty lashes with a wet noodle.

> But the the code can never parse N anyways, because sooner or later
> even a std::vector runs out of memory space.

Oh, come now. By that reasoning, code using std::vector can never do
anything with N.

> I simply find it hard to accept that a predefined maximum capacity,
> being at compile time or runtime, should run into undefined behaviour
> if that capacity is exceeded. There's too much code in the world
> already that doesn't check limits. STL containers has helped
> tremendously in this regard,

Huh? Except for at(), STL containers aren't spec'd to check for misuse
or out-of-bounds access. The ones that do check are doing so... **as an
expression of undefined behavior**.

> I don't see why one would want to go in another direction.

That's why I'm specifically proposing a mode that *does* do the
checking. But we should *not* encode into the library spec that the
response to a failed check is an exception in those cases where a failed
check is most likely to represent a programming error.

-- 
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

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