From: Daniel Krügler on
On 18 Jul., 05:24, Michael Kilburn <crusader.m...(a)gmail.com> wrote:
> Hi,
>
> I have checked C++ standard and did not find requirements imposed on
> library implementation with respect to exception safety. But this is
> as important of other parts of contract between library and client set
> in standard. E.g. if program relies on strong guarantee provided by
> some operation and another STL implementation provides only basic --
> this program is not C++ program (in a sense that compiled in different
> standard-compliant environment it will behave differently).

There exist some very general statements and guarantees, see below.

> Did I miss some standard addendum or followup papers?

Surely, but none of them is relevant for the C++ standard.
Unless an ISO standard particularly refers to some other
standard, no such statements/guarantees could be imposed
on a compiler satisfying the standard.

> Can someone point me to right direction, please?

Some examples (all referring to ISO/IEC 14882:2003(E)):

1) 17.4.3.6/2:

"In particular, the effects are undefined in the following cases
[..]
� if any replacement function or handler function or destructor
operation throws an exception, unless specifically allowed in
the applicable Required behavior paragraph."

2) 17.4.4.8/2+3:

2 None of the functions from the Standard C library shall
report an error by throwing an exception, unless it calls
a program-supplied function that throws an exception.

3 No destructor operation defined in the C++ Standard Library
will throw an exception. Any other functions defined in the
C++ Standard Library that do not have an exception-specification
may throw implementation-defined exceptions unless otherwise
specified. [..]

3) 20.4.4/1:

"[..] In the following algorithms, if an exception is thrown
there are no effects."

4) 21.1.1/1:

"[..] Operations on Traits shall not throw exceptions."

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.
� if an exception is thrown by a push_back() or push_front()
function, that function has no effects.
� no erase(), pop_back() or pop_front() function throws an
exception.
� no copy constructor or assignment operator of a returned
iterator throws an exception.
� 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).[..]"

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."

Remark: While this is a seemingly non-normative note in C++03
the intend was to make this a normative requirement. This
state has been fixed in C++0x.

7) 23.2.1.3/6:

"Throws: Nothing unless an exception is thrown by the copy
constructor or assignment operator of T."

8) 23.2.2.3/1:

"Notes: [..] If an exception is thrown there are no effects."

(See bullet 5)

9) 23.2.2.4/16:

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

10) 23.2.2.4/31:

"Notes: Stable: the relative order of the equivalent elements
is preserved. If an exception is thrown the order of the
elements in the list is indeterminate."

(See bullet 5)

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.

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 19 Jul., 08:27, Michael Kilburn <crusader.m...(a)gmail.com> wrote:
> 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!

If they are incomplete in the sense that the standard is ambiguous
or contradictory in this regard this would be an issue, yes.

> 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?

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.

> > � 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?

Unless the standard does give a concrete statement that
their are no effects, the state of an object after an exception
thrown by user-code is unspecified, but valid. [Note that the
standard does give general freedom for user-code to
throw exceptions and does only mention explicitly those
situations where undefined behavior would follow from
such action].

I know, the standard doesn't say so explicitly, but it's IMO
the only reasonable interpretation of 17.6.3.8 (FCD):

1 In certain cases (replacement functions, handler functions,
operations on types used to instantiate standard library
template components), the C++ standard library depends
on components supplied by a C++ program. If these
components do not meet their requirements, the Standard
places no requirements on the implementation.

2 In particular, the effects are undefined in the following cases:
[..]
� if any replacement function or handler function or destructor
operation exits via an exception, unless specifically allowed in
the applicable Required behavior: paragraph.

The indirect effect of these rules is that any exception thrown
by user-code within a hosting library component must at
least satisfy the basic exception guarantees for this component.
Sometimes the guarantees are stronger and thus are mentioned
by additional wording. These are the parts which I quoted.

> > 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?

The implied effect is, that the state is unspecified (but valid).
Note that C++0x has strengthened this situation as of 23.3.2.3/2:

"Remarks: If an exception is thrown other than by the copy
constructor, move constructor, assignment operator, or
move assignment operator of T there are no effects. If an
exception is thrown by the move constructor of a non-
CopyConstructible T, the effects are unspecified."

> > 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)

The effects are unspecified in this case. You should use a
node-based container, if you need more (In this case the
general no-throw-remark for erase() holds).

> 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.

I don't agree with that general statement. I agree that some parts
could be improved in wording, but the foundation is given.
E.g. if it is important for you that std::vector<std::string>::erase
does
not throw, you should use a type with non-throw move, which
is the typical case, I would say (Note that clear() now guarantees
that it does not throw for any container anyway). Or use a
node-based container like list, if you need even more.

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: Howard Hinnant on
On Jul 25, 7:55 pm, n...(a)cam.ac.uk wrote:
> In article
> <35c20875-6842-4b5c-9386-9499c3858...(a)f6g2000yqa.googlegroups.com>,
> Howard Hinnant <howard.hinn...(a)gmail.com> wrote:
>
> >Many people don't realize that it is relatively easy to add features
> >when using a minimal & fast library - making an informed engineering
> >tradeoff between features and performance. But when given a feature-
> >rich library (without access to a low-level API), one can't make it
> >fast when you don't need the features. Doing so is a common mistake
> >in library design: forgetting or dismissing the importance of the low-
> >level layer.
>
> That is extremely true, but is in flat contradiction to what the
> OP asked for, and what I understood Dragan Milenkovic to mean.
>
> The same is true for RAS, only even more so, and yet more for actual
> recovery. It is a common and catastrophic mistake to think that
> either are features, because they are not, and cannot be built on
> top of a design that doesn't have them. They are fundamental
> properties of the base design and implementation.
>
> There is NO WAY that a programmer can add recovery facilities to
> the current STL. An implementor can - but, to make it usable, has
> to specify its properties and constraints - i.e. design an extended
> STL standard.

After reading your post I got the feeling that I had overlooked a
proposed design for an extended STL standard in this thread. So I
reread the thread but somehow am still missing it. I look forward to
reading a detailed proposal for an extended STL standard.

-Howard


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

From: Mathias Gaunard on
On Jul 26, 12:55 am, n...(a)cam.ac.uk wrote:

> There is NO WAY that a programmer can add recovery facilities to
> the current STL. An implementor can - but, to make it usable, has
> to specify its properties and constraints - i.e. design an extended
> STL standard.

It is fairly trivial to write a wrapper of std::vector<T>::insert for
example that provides strong exception safety, so I don't see what you
mean by "there is NO WAY" to do it.
Technique is simple: build another temporary vector, then if all went
well swap (which is nothrow). That technique can be virtually applied
in all cases you'd want to make a primitive strongly exception-safe.


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

From: nmm1 on
In article <2e2dc884-1d87-4a0e-a5d8-5a4515d04dd3(a)d37g2000yqm.googlegroups.com>,
Mathias Gaunard <loufoque(a)gmail.com> wrote:
>On Jul 26, 12:55 am, n...(a)cam.ac.uk wrote:
>
>> There is NO WAY that a programmer can add recovery facilities to
>> the current STL. An implementor can - but, to make it usable, has
>> to specify its properties and constraints - i.e. design an extended
>> STL standard.
>
>It is fairly trivial to write a wrapper of std::vector<T>::insert for
>example that provides strong exception safety, so I don't see what you
>mean by "there is NO WAY" to do it.
>Technique is simple: build another temporary vector, then if all went
>well swap (which is nothrow). That technique can be virtually applied
>in all cases you'd want to make a primitive strongly exception-safe.

Er, no. Let's ignore minor details like the impracticability of
that in many cases, and the fact that wrapping and code replacement
are just two sides of the same coin. If I have to faff around like
that, I may as well write my own class, which would be more efficient
and safer. In any case, your statement is false unless the standard
mechanism already provides basic exception safety, which isn't the
case everywhere, as far as I can see.

There are several killers.

The first is 1.3.13 in n3092: "Undefined behaviour may also be
expected when this International Standard omits the description of
any explicit definition of behaviour." As Bjarne's Appendix E
(Standard-Library Exception Safety) shows, there is a very patchy
collection of guarantees.

My previous question about the requirements on the semantics of
STL constructores confirmed that there is a lot that is simply not
stated explicitly. And, sorry, but "but everybody knows that" is
explicitly against ISO rules and a disaster for RAS and portability.

Related to this is the complexity of the wording, which is a firm
guarantee that some aspects will be missed by almost all programmers,
implementors and even in the standard itself. I am still trying to
track down WHERE it says certain things that experts (like Bjarne
and Howard) have said are specified. Like the "no memory leaks"!

There is also the major problem that a lot of the 'guarantees' are
actually very harsh constraints on the use of the library - e.g.
the number of things that are not allowed to throw, even though
there are potentially unavoidable exceptions in them. Related to
this is the implicit restriction that all asynchronous exceptions
are undefined behaviour. That's not realistic, in practice.

The traditional definition of "exception safety" was that the
behaviour was defined and "reasonable", no matter what raised an
exception - INCLUDING when one was raised asynchronously. As I
said, that might mean that an item might be either inserted or not,
or a sort had part-completed, but those can be used as a basis for
recovery.

A specification that exceptions raised under some circumstances are
safe, but others (equally likely to arise) lead to undefined behaviour
isn't something that I would want to build a high-RAS system on.


Regards,
Nick Maclaren.

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