Re: Is there any standard/guarantees for exception safety in STL operations?
On 19 Jul., 08:27, Michael Kilburn <crusader.m...@gmail.com> wrote:
On Jul 18, 3:29 pm, Daniel Kr?gler <daniel.krueg...@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! ]