Re: Is exception-safety possible at all?
on Mon Jan 19 2009, Adam Badura <abadura-AT-o2.pl> wrote:
So lets consider a different example:
class Operation
{
public:
void commit(); // may throw
void rollback(); // will never throw
};
void f( std::vector< Operation >& vec )
{
typedef std::vector< Operation >::iterator iterator;
typedef std::vector< Operation >::reverse_iterator
reverse_iterator;
const iterator end = vec.end(); // (1)
iterator it = vec.begin(); // (2)
try
{
for ( ; it != end; ++it ) // (3)
it->commit(); // (4)
}
catch ( ... )
{
const reverse_iterator rend = vec.rend(); // (5)
reverse_iterator rit = it; // (6)
for ( ; rit != rend; ++rit ) // (7)
rit->rollback(); // (8)
}
}
From my personal experience this code is considered to be exception-
safe (basic guarantee).
Actually this code is nothrow, but assuming you meant to rethrow at the
end of the catch block... ;-)
Yes.
If "commit" and "rollback" are understood according to intuition then
this is exception-safe code in the strong meaning.
Nope.
But in my opinion it is not. This is why:
- (5) may fail. Although 23.1$10 says that "no copy constructor or
assignment operator of a returned iterator throws an exception" it
does not say so about "rend" (or "rbegin", "begin" and "end"...). And
in fact for some containers it might fail (because of lack of memory
for example for some data required by the iterator). But Standard does
not put any restriction on vector so for vector it might fail as well.
Yes.
- (6) may fail. Construction of "reverse_iterator" from iterator may
throw.
Hmm, probably true, and unfortunate.
- (7) may fail. operators != and ++ might both throw.
Hmm, right again, and unfortunate in light of your example.
- (8) may fail. operator -> might throw.
Yep.
Thus this code (in "catch") might very well not be executed correctly
to the end. Strong guarantee is lost. Also whil throwing it will mask
original exception so transparency is lost.
Yep.
Basic guarantee is held. However i suppose I could find a more fancy
example where even the basic guarantee would be lost.
Probably.
Obviously switching to iterating with -- in "catch" will not change
much as that could still could throw. The same is true when iterating
with index types. First of all index type for vector is size_type and
it might be any type - not only basic type (if I am not mistaken).
Further more even if it would be integer type any arithmetic operation
or comparison might throw as well (even if for valid arguments)
because Standard does not prohibit it (or does it? - where then?).
If a given implementation behavior is not explicitly permitted, it is
outlawed. The standard specifies the behavior of the biult-in integers
(by reference to the C98 standard).
--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]