Re: Is this exception-safe code template correct?
On Jan 10, 8:35 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
On 10/01/10 01:25, DeMarcus wrote:
Hi!
David Abrahams introduced the exception safety guarantees.
http://www.boost.org/community/exception_safety.html
In order to easier create exception safe code I have written a function
code template (a mind template, *not* a C++ template) that I can give to
colleagues, friends, you (if you want), and myself. In the code I have
used Petru Marginean's and Andrei Alexandrescu's ScopeGuard.
http://www.ddj.com/cpp/184403758
The function code template looks like this.
SomeType function( SomeType argument )
{
// Beginning of irreversible, throwing code.
// Non-leaking code here gives Basic Guarantee [D.Abrahams].
// Beginning of reversible, throwing code.
// Code starting here gives Strong Guarantee.
exampleVector_.push_back( "Something" );
ScopeGuard guard1 = makeScopeGuard( exampleVector_,
&std::vector<std::string>::pop_back );
exampleList_.push_back( "Something else" );
ScopeGuard guard2 = makeScopeGuard( exampleList_,
&std::list<std::string>::pop_back );
// ... more code. Only the last operation does not need
// a ScopeGuard.
guard1.dismiss();
guard2.dismiss();
// Beginning of irreversible, non-throwing (non-failing) code.
// Code only here gives No-throw Guarantee.
return;
}
I would gladly hear your comments about it so I can improve it to be
perfect. Please give your thoughts, first and foremost, about how to
write good comments that will guide the programmer to fill in correct
code at correct places. Also if you have ideas how tools like ScopeGuard
can be used, that is welcome too.
In the above code it may be easier to put rollback code in an exception
handler:
SomeType function( SomeType argument )
{
enum { STAGE_0, STAGE_1, STAGE_2 } stage = STAGE_0;
try { // do code
exampleVector_.push_back( "Something" );
stage = STAGE_1;
exampleList_.push_back( "Something else" );
stage = STAGE_2;
// ...
} catch(...) { // reverse order undo code
switch(stage) {
case STAGE_2: exampleList_.pop_back();
case STAGE_1: exampleVector_.pop_back();
default: break;
}
throw;
}
}
This approach is a bit lower level, but, I think, it provides much
greater flexibility than a scope guard.
(DeMarcus, I see no problem with what you wrote there).
Maxim, your approach is indeed what happens with scope guard code, but
done explicitly.
The problem with it, IMO, is that it adds incidental complexity:
"stage" enum, try/catch, switch, and throw. Scope guard only adds
"dismiss" lines at end. I also think that it's beneficial to have
scope guard close to the "guarded" code, for the purpose of having
these related things close by. It is kinda backwards because it's code
is executed at end, but hey, perfection is in the eye of beholder ( or
something like that ;-) ).
Goran.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]