From: DeMarcus on
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.


Thanks,
Daniel

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

From: Maxim Yegorushkin on
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.

If scope guards are good enough for you, you might be interested in
Boost.ScopeExit
http://www.boost.org/doc/libs/1_41_0/libs/scope_exit/doc/html/scope_exit/tutorial.html

--
Max




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

From: Goran on
On Jan 10, 8:35 pm, Maxim Yegorushkin <maxim.yegorush...(a)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! ]

From: DeMarcus on

> 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 just hit me that ScopeGuards may be exception-unsafe!
Look at this code.

exampleVector_.push_back( "Something" );
ScopeGuard guard1 = makeScopeGuard( exampleVector_,
&std::vector<std::string>::pop_back );

What if makeScopeGuard throws?! It won't in this particular example, but
if the function to makeScopeGuard is a functor or if it takes
parameters, any of these may throw when copied. Then we have done an
irreversible push_back.

Mustn't we reverse the order to the following?

ScopeGuard guard1 = makeScopeGuard( exampleVector_,
&std::vector<std::string>::pop_back );
exampleVector_.push_back( "Something" );

If so, then it's also wrong in the original article by Alexandrescu &
Marginean.
http://www.ddj.com/cpp/184403758

Or am I thinking wrong?






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

From: Goran on
On Jan 12, 1:17 am, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote:
> > 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 just hit me that ScopeGuards may be exception-unsafe!
> Look at this code.
>
> exampleVector_.push_back( "Something" );
> ScopeGuard guard1 = makeScopeGuard( exampleVector_,
> &std::vector<std::string>::pop_back );
>
> What if makeScopeGuard throws?! It won't in this particular example, but
> if the function to makeScopeGuard is a functor or if it takes
> parameters, any of these may throw when copied. Then we have done an
> irreversible push_back.
>
> Mustn't we reverse the order to the following?
>
> ScopeGuard guard1 = makeScopeGuard( exampleVector_,
> &std::vector<std::string>::pop_back );
> exampleVector_.push_back( "Something" );
>
> If so, then it's also wrong in the original article by Alexandrescu &
> Marginean.http://www.ddj.com/cpp/184403758
>
> Or am I thinking wrong?

In general, with exceptions, IMO thinking goes like this: anything can
throw, except code that is __specially crafted not to__. Tpical
examples: primitive type assignments, pointer arithmetic and
assignment, non-throwing swap etc. And in that light, guard creation
should be is written so that it is has no-throw guarantee[1]. But that
is achieved through programmer's engagement. And that does mean that
one must avoid copy constructors that might throw. Luckily, that is in
practice not hard to do, for two reasons:

1. you will seldom have such parameters to scope guards, because what
you typically want done are lower-level cleanup operations,
2. if you do, you will probably want them passed by reference (the
ByRef function in the article), and that should exclude constructor
calls.

I don't like the idea of putting scope guard in front of the "guarded"
code. For example, your guard will often use guarded code results,
e.g.

handle h = get_handle(params);
ON_BLOCK_EXIT(&release_handle, h);
do_work();

So if you are tempted to do the guard before, that would become:

handle h=INVALID;
ON_BLOCK_EXIT(&release_handle, ByRef(h));
h = get_handle(params);
do_work();

Which is less "natural" than first version, requires ByRef, and
requires that release_handle works OK with INVALID, which may or may
not be the case.

Goran.

P.S. Perhaps the original article should contain a big warning about
invoking copy constructors when making a guard. ;-)

[1] http://en.wikipedia.org/wiki/Exception_handling#Exception_safety


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