From: Bo Persson on
Thomas Richter wrote:
> Francis Glassborow wrote:
>
>> For example suppose that you try to insert a block of ten elements
>> into a container and that an exception is thrown during this
>> process. You will still have a stable container in a destructable
>> state. However the Standard does not guarantee that it is in the
>> same state that it was prior to your attempt to insert elements.
>
> Certainly, that is understood. But assume that the copy
> constructors of my classes cannot throw (otherwise, of course, I
> agree that all bets are off, and my code is to blame, and not the
> STL). However, even then the STL does not ensure that the container
> is in a state where either all new elements are present, or it
> remained in the original state. I can certainly arrange that
> (insert, swap), but without knowing the implementation of insert,
> not in a way that is as efficient as it could. Clearly, such an
> implementation would be slower (needless to say), but still
> required to write code that provides a "useful" guarantee in case
> of exceptions.

If you look at the various container types, you will see that the
requirements are slightly different for each type. The STL has already
taken into account what can and cannot be done.

In the vector example you just HAVE to copy all elements if the
current buffer is to small. There is no way to construct new elements
separately, and append them later. However, there is a way to do that
for std::deque...

>
> Or to make it more concrete: Assume that I can ensure you that my
> copy constructor doesn't throw, *how* should I deal with exceptions
> I get from insert()? Basically, I cannot handle them since I do not
> know what the state of the object is after insertion (except that
> it is to some degree valid, syntactically at least, but not
> semantically). Thus, what should I do then - really as a practical
> advice?


You DO get an assurance that if anything else throws, like a
std::bad_alloc, a std::vector will be unchanged.

If your copy constructor or assignment throws, the container will
fail, but how the heck would you "fix up" the elements that couldn't
be assigned? How are you going to assign them valid values, when
assignment throws?

Most of the operations are optimized for the non-throwing case. A lot
of them can be written in an exception-neutral way, so that any
exceptions thrown will not have to be catch'ed by the library. If you
look into the library, there are very few try-catch statements outside
the stream library. If the library is to report "exception thrown when
inserting object 42", the exception would first have to be caught, at
extra cost.


> Realistically, I can only terminate, or scan the object fully to
> find what is inserted and what is not. Or I must build a copy/swap
> around it. Neither solution is attractive, though knowing the STL
> implementation, finding such "stale elements" might be simpler or
> even trivial.

No, it all depends on what your application is doing. Assume that the
container is used as a cache for some computed values. If the
insertion fails, you could just delete the container and start over.
Or back out a database or web server request, and try the next one.


Bo Persson



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

From: Thomas Richter on
Bo Persson wrote:

>
> If you look at the various container types, you will see that the
> requirements are slightly different for each type. The STL has already
> taken into account what can and cannot be done.
>
> In the vector example you just HAVE to copy all elements if the
> current buffer is to small. There is no way to construct new elements
> separately, and append them later. However, there is a way to do that
> for std::deque...

> If your copy constructor or assignment throws, the container will
> fail, but how the heck would you "fix up" the elements that couldn't
> be assigned? How are you going to assign them valid values, when
> assignment throws?

I don't think I was asking for that (in case I throw, I mean), but well,
for example the STL could document (or provide a function for that)
which tells me in which order elements have been inserted, and how many
insertions have been performed before throwing. Doesn't seem overly hard
to do, but would allow a much better recovery.

> Most of the operations are optimized for the non-throwing case. A lot
> of them can be written in an exception-neutral way, so that any
> exceptions thrown will not have to be catch'ed by the library. If you
> look into the library, there are very few try-catch statements outside
> the stream library. If the library is to report "exception thrown when
> inserting object 42", the exception would first have to be caught, at
> extra cost.

That's not exactly what I was asking. I don't mind if exception recovery
takes time or is complex, but at least, it should be reasonably possible.


>> Realistically, I can only terminate, or scan the object fully to
>> find what is inserted and what is not. Or I must build a copy/swap
>> around it. Neither solution is attractive, though knowing the STL
>> implementation, finding such "stale elements" might be simpler or
>> even trivial.
>
> No, it all depends on what your application is doing. Assume that the
> container is used as a cache for some computed values. If the
> insertion fails, you could just delete the container and start over.
> Or back out a database or web server request, and try the next one.

Sure, but maybe I need a different recovery strategy. And then I have
little means of implementing one. That's what I'm saying.

So long,
Thomas

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

 | 
Pages: 1
Prev: U++ Tutoring Plan
Next: Any hopes for export ?