From: Michael Kilburn on
On Jul 18, 3:29 pm, Daniel Kr�gler <daniel.krueg...(a)googlemail.com>
wrote:
> > I have checked C++ standard and did not find requirements imposed on
> > library implementation with respect to exception safety.
> > ...
>
> There exist some very general statements and guarantees, see below.

Yes, I saw them... the problem is that quite often they are not "very
general" -- they are incomplete! I'll quote an example from those
provided by you:


> 5) 23.1/10:
>
> "Unless otherwise specified (see 23.2.1.3 and 23.2.4.3) all
> container types defined in this clause meet the following
> additional requirements:
> � if an exception is thrown by an insert() function while
> inserting a single element, that function has no effects.

.... and what if we are inserting more than one element? what effect(s)
we are going to have?


> � no swap() function throws an exception unless that exception
> is thrown by the copy constructor or assignment operator of
> the container�s Compare object (if any; see 23.1.2).[..]"

.... and what is going to happen to the object?


> 6) 23.2.1.3/2:
>
> "Notes: If an exception is thrown other than by the copy
> constructor or assignment operator of T there are no effects."

.... and what if it is thrown by assignment operator?


> 7) 23.2.1.3/6:
>
> "Throws: Nothing unless an exception is thrown by the copy
> constructor or assignment operator of T."

.... and what if it is thrown by T::operator=() -- how object *must*
behave? How I can use std::vector<std::string> if there is no
guarantee that it will behave in the same way with all compilers? (we
know that std::string::operator=() can throw std::bad_alloc)


> 9) 23.2.2.4/16:
>
> "Throws: Nothing unless an exception is thrown by *i == value
> or pred(*i) != false."

.... same thing here


> I'm stopping here, but it is quite easy to find the relevant
> locations in the wording by searching for the word "exception"
> in the document.

Thank you Daniel for helping with this. But as I pointed above it
seems that C++ has a deficiency in a sense that it often does not
describe calling contract completely. And this prevents us from
claiming that given C++ program is correct and/or reliable.
I think this is sad. All these fancy-shmancy features we have been
hearing for last 10 years, but at the same time STL (main library I'd
say after CRT) is not properly standartised.


Thank you.
Michael.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Michael Kilburn on
On Jul 19, 7:01 am, Francis Glassborow
<francis.glassbo...(a)btinternet.com> wrote:
> > the problem is that quite often they are not "very
> > general" -- they are incomplete!
>
> In one sense they are incomplete, but in another they say as much as can
> be reasonably said and the programmer has to note what is guaranteed.

I think to write robust program all aspects of calling contracts
should be defined. You might argue that I should "assume the worst" if
standard omits particular aspect. But:
- this is tiring -- trying to find whether particular aspect was
omitted or just mentioned elsewhere in standard
- what is "worst" in this case -- undefined behaviour? basic
guarantee? minimal? (I think standard was written when last two
concepts were not even formed yet) If I assume "worst"=="undefined
behaviour" -- I won't be able to use things like vector<string>.


Stepping aside this is a big problem in C++, imho -- because we use
exceptions mechanism that ensures that error is not going to be
ignored, paradoxically most people ignore possible execution paths
created by exceptions, assuming that it will "work out somehow, we'll
catch everything higher on the stack"... How many programs you've seen
that correctly handle exception thrown from
vector<string>::insert? ;-)


> >> 5) 23.1/10:
>
> >> "Unless otherwise specified (see 23.2.1.3 and 23.2.4.3) all
> >> container types defined in this clause meet the following
> >> additional requirements:
> >> - if an exception is thrown by an insert() function while
> >> inserting a single element, that function has no effects.
>
> > ... and what if we are inserting more than one element? what effect(s)
> > we are going to have?
>
> What can it say? In general it will not be able to return to the
> original so if it matters the programmer must adopt a different strategy
> if exceptions could be thrown and you require a strong guarantee. To
> require a strong guarantee would impose an unreasonable burden on
> everyone who does not care or who knows that an exception cannot be
thrown.

No, I don't need strong guarantee here. I need a guarantee of some
behavior. It can say that it provides basic guarantee, or minimal, or
strong, I don't care -- in any case I will end up with guarantee of
behavior and I will be able to structure my code in such way that it
will always behave on standard-compliant system.


> >> - no swap() function throws an exception unless that exception
> >> is thrown by the copy constructor or assignment operator of
> >> the container's Compare object (if any; see 23.1.2).[..]"
>
> > ... and what is going to happen to the object?
>
> If you insist on having a copy ctor or an assignment operator that can
> throw in the circumstances detailed then it is unreasonable to require a
> strong guarantee.

I don't need a strong guarantee. I need well-defined behaviour.


> >> 6) 23.2.1.3/2:
>
> >> "Notes: If an exception is thrown other than by the copy
> >> constructor or assignment operator of T there are no effects."
>
> > ... and what if it is thrown by assignment operator?
>
> See above. Note that most copy ctors and copy assignments do not throw.

:-) I think you need to provide some context here... In my experience
most cctors and op='s throw.


> I think that the problem is that you would like guarantees that could
> only be provided at a high cost to everyone. I think that if you try to
> implement containers such as vector<> with a strong guarantee for all
> operations you will realise why the Standard does not make this promise.
> It can be done but the cost would be so high that few would want to pay
> it if they did not have to.

No, I do not ask for strong guarantees everywhere. All I need is
defined behavior of standard's subjects in all circumstances -- and it
should be clearly stated in document and easy to find.

Implementations are free to provide more (i.e. strong guarantee when
standard promises only basic) -- this is fine (though it would be nice
to be able to detect this at compile time).

Thank you.
Michael.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Joshua Maurice on
On Jul 19, 5:01 am, Francis Glassborow
<francis.glassbo...(a)btinternet.com> wrote:
> Michael Kilburn wrote:
> > On Jul 18, 3:29 pm, Daniel Kr�gler <daniel.krueg...(a)googlemail.com>
> >> 6) 23.2.1.3/2:
>
> >> "Notes: If an exception is thrown other than by the copy
> >> constructor or assignment operator of T there are no effects."
>
> > ... and what if it is thrown by assignment operator?
>
> See above. Note that most copy ctors and copy assignments do not throw.

While I agree with the rest of your snipped post, I might take issue
with this. I would remind you that operator new, by default, can throw
an exception. Thus a lot of operations on simple things like
std::vector, std::string, printf, and more, can throw an exception.
>From my limited experience, for most programs intended for desktops
and not embedded systems, a lot more functions than one might think
actually can throw an exception, namely std::bad_alloc.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel Krügler on
On 20 Jul., 06:45, "Peter C. Chapin" <pcc482...(a)gmail.com> wrote:
> On 2010-07-19 15:51, Daniel Kr�gler wrote:
>
> >>> � if an exception is thrown by an insert() function while
> >>> inserting a single element, that function has no effects.
>
> >> ... and what if we are inserting more than one element? what effect(s)
> >> we are going to have?
>
> > The above quoted wording was intentionally restricted to the
> > "one-element" insertion, so this is not incomplete. It was
> > decided that a type satisfying a container type is not required
> > to ensure the strong exception guarantee for multiple
> > element insertions. User-provided container types can easily
> > strengthen this requirement, if necessary.
>
> The standard explains what happens if an exception is thrown during a
> single element insertion, but appears to be silent about the multiple
> element case (true?). Okay, so inserting multiple elements does not
> provide the strong guarantee, but what sort of guarantee does it
> provide?

In non-normative wording: It provides the basic guarantee as described
before. I.e. the state is valid, but unknown.

> Is the result UB? Is an implementation permitted to reformat my
> hard drive in that case?

The result is *no* UB and there is no valid state that is supposed to
reformat your hard drive.

As mentioned before: The library is in general prepared that user-code
may throw exceptions. It explicitly mentions those situations, where
it may not, e.g. it may never throw exceptions in destructors that
are called within library code (e.g. as part of destroying a
container).

Note how 17.6.3.8/2 (FCD) does specifically mention exception:

"In particular, the effects are undefined in the following cases:
[..]
� for types used as template arguments when instantiating a template
component, if the operations on the type do not implement the
semantics
of the applicable Requirements subclause (20.2.5, 23.2, 24.2, 26.2).
Operations on such types can report a failure by throwing an
exception
unless otherwise specified.
� if any replacement function or handler function or destructor
operation
exits via an exception, unless specifically allowed in the applicable
Required behavior: paragraph.
[..]"

Please note the sentence:

"Operations on such types can report a failure by throwing an
exception
unless otherwise specified"

which is a general statement *including* user-defined types ("types
used
as template arguments").

And please note the follow-up bullet, which makes exceptions leaving
destructors, replacement functions, or handler functions in general
boo-boo (UB) *unless* explicitly allowed. One such explicit allowance
is
that for the handler function for set_unexpected_handler in 15.5.2/3:

"The std::unexpected() function shall not return, but it can throw (or
re-
throw) an exception. [..] If it throws or rethrows an exception that
the
exception-specification does not allow then the following happens: If
the
exception-specification does not include the class std::bad_exception
(18.8.2.1) then the function std::terminate() is called, otherwise
the
thrown exception is replaced by an implementation-defined object of
the type std::bad_exception and the search for another handler will
continue at the call of the function whose exception-specification
was
violated."

or for the replacement forms of the global allocation functions, e.g.
18.6.1.1/3:

"Required behavior: Return a non-null pointer to suitably aligned
storage
(3.7.4), or else throw a bad_alloc exception. This requirement is
binding
on a replacement version of this function."

etc. The conclusion from this is, that a general *throw-allowance* is
given
but the standard does not explicitly say what the state will be after
this
This is not different than saying that the state is "unknown but
valid".

I agree that this last conclusion is only indirect, but IMO the only
reasonable one.

Additional to this "basic exception guarantee" the standard sometimes
requires more by giving additional (stronger) guarantees. These
situations
do typically describe a state that we can informally describe as
"strong
exception guarantee". The only "exception" I found from this rule
(there maybe some others lurking around) during a quick survey of the
FCD is the normative description of forward_list::sort, 23.3.3.5/22:

"Effects: [..] If an exception is thrown the order of the elements in
*this
is unspecified."

IMO it would be better to strike this one, because it doesn't say
anything
new and causes irritations when comparing with the lack of these extra
guarantees.

HTH & Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel Krügler on
On 21 Jul., 15:04, Michael Kilburn <crusader.m...(a)gmail.com> wrote:
> I'll skip most of the quoting and will try to summarize all these
> postings -- so you are saying that:
> 1) unless explicitly specified otherwise any STL operation provides
> basic exception guarantee

While thinking of it: Iterators are a rather underspecified in this
regard. The standard does not say so explicitly, but I think that
a container with iterators that potentially throw exceptions
won't even provide the basic guarantee (in general).

> 2) there are no cases on unspecified behaviour other than 3 you
> mentioned (exception from dtor, replacement and handler functions)

Exceptions from dtor, replacement, and handler functions cause
undefined behaviour, not unspecified behaviour. And: No: I cannot
*promise* you that there is no unspecified behaviour left ;-)

> 3) there are places where strong guarantee is guaranteed and mentioned
> explicitly

This is correct.

> Are those point correct?

I cannot provide your any guarantee, especially I cannot give you the
guarantee of completeness. 17.6.4.11 (FCD) lists some further
constraints, e.g. C-functions shall not throw exceptions unless
they are customized by user-provided functions that might throw
(e.g. qsort and bsearch can handle exceptions from the compare
function). But note that handlers provided to atexit which throw
exceptions will provoke terminate.

> What are the "replacement and handler functions" -- functors I pass
> into std::transform/etc?

No. /Handler functions/ are only those mentioned in 17.6.3.7, i.e.
user-provided function pointers provided to set_unexpected,
set_new_handler, and set_terminate. /Replacement functions/ are
those mentioned in 17.6.3.6, i.e. the user-provided replacements
for global operator new/delete (all forms).

Normal functors may throw what they like (unless specified
elsewhere...)

> Would be really nice to have a shortlist of cases where STL gives
> strong guarantee. Plus readable explanation for undefined behaviour
> cases. It is quite painful to extract this infromation from standard
> right now.

I suggest that someone interested writes a book and gets the money
he or she deserves for that - the good thing is: This book will always
require updates ;-)

> And this, of course, contributes to current state of things
> in industry, where 80% of senior level developers do not know what is
> going to happen if while throwing exception another exception gets
> produced (I did a lot of interviews lately (not as a candidate :-)))
> and host of apps that goes bananaz when something goes wrong (like out
> of memory).

I won't deny that the standard as a document is hard to read and
hard to interpret. It's mainly written for technicians that are
supposed
to implement a compiler or a standard library. I also agree that
specifying exception guarantees is not on it's top priority list,
even
though the situation has (slightly) improved over the years.

HTH & Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]