Prev: What are requirements for allocator destructor?
Next: Is there any standard/guarantees for exception safety in STL operations?
From: Daniel Krügler on 18 Jul 2010 05:29 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 19 Jul 2010 04:51 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 25 Jul 2010 23:11 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 26 Jul 2010 02:45 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 26 Jul 2010 07:48
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! ] |