Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

is RAII really always the better choice ?

21 views
Skip to first unread message

Roshan Naik

unread,
May 4, 2005, 6:34:38 AM5/4/05
to
I know that using the finally block (in Java or C#) to dispose resources is
considered inferiror to RAII.
However I recently came accross a little C++ example that used some
compiler's __finally language extension
that made me rethink there might be some value in finally...sometimes.

The code was something to this effect (roughly)....

mouse.setCursor(HOUR_GLASS); // change state
try {
doSomeTimeConsumingWork( );
}
__finally { // non standard extension
mouse.setCursor(NORMAL_POINTER); //reset state
}


Clearly there is no resrouce acquisistion/disposal going on here. Just
change some state , do some work, and then reset the state.
And here RAII can be put to work (and ScopeGuard comes to mind), but it is
not at all natural to use destructors for doing such things. That
immediately feels more like a hack.... and hides the intent of the code
somewhere behind the scenes.

Also it seems useful in cases where you want to guarantee the restoration of
an invariant.

-Roshan


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

Bronek Kozicki

unread,
May 4, 2005, 7:57:24 AM5/4/05
to
Roshan Naik <som...@somehwere.com> wrote:
> However I recently came accross a little C++ example that used some
> compiler's __finally language extension

Microsoft Visual C++ family of compilers provides exception handling in
C (as opposed to C++) through compiler extensions and OS facilities
called Structured Exception Handling (SEH). These extensions are not
disabled when compiling C++ code. Nevertheless, they do not have much
use in C++, as documentation for MSVC clearly states. But for C code,
these are as much valuable as "try ... finally" for Java. I suppose that
you found this code in C project or project (partly) ported from C, or
code written by someone accustomed to this (quite old) exception
handling mechanism and/or not familiar with RAII.

Having said that, there are situations when this mechanism has good use
also in C++ code directed on Windows platform - that is because some OS
specific functions might throw SEH exception in well-defined conditions
(examples in documentation of InitializeCriticalSection, MapViewOfFile
etc).

> Clearly there is no resrouce acquisistion/disposal going on here. Just
> change some state , do some work, and then reset the state.
> And here RAII can be put to work (and ScopeGuard comes to mind), but
> it is not at all natural to use destructors for doing such things.

> That immediately feels more like a hack.... and hides the intent of
> the code somewhere behind the scenes.

RAII would not be hack at all, at least for me. You acquire resource
(cursor) and then release it (reset cursor to normal state) when you are
done.


B.

Nemanja Trifunovic

unread,
May 4, 2005, 10:09:54 AM5/4/05
to
> The code was something to this effect (roughly)....

mouse.setCursor(HOUR_GLASS); // change state
try {
doSomeTimeConsumingWork( );
}
__finally { // non standard extension

mouse.setCursor(NORMAL_POINTER­); //reset state
}

Funny you mention this as an example. In MFC, there is a class called
CWaitCursor that uses RAII exactly for that puropse.

j_ri...@gmx.de

unread,
May 4, 2005, 11:09:25 AM5/4/05
to
Roshan Naik schrieb:

> The code was something to this effect (roughly)....
>
> mouse.setCursor(HOUR_GLASS); // change state
> try {
> doSomeTimeConsumingWork( );
> }
> __finally { // non standard extension
> mouse.setCursor(NORMAL_POINTER); //reset state
> }
>
>
> Clearly there is no resrouce acquisistion/disposal going on here.
Just
> change some state , do some work, and then reset the state.
> And here RAII can be put to work (and ScopeGuard comes to mind), but
it is
> not at all natural to use destructors for doing such things.

I think this is a very good example to use an object. It has several
advantages. You write only 1 line instead of 6. The code becomes
something like this:

{
HourClassCursor hcc;
doSomeTimeConsumingWork();
}

And not to forget. After you've inserted a lot of your code snipets in
different functions you later discover that this doesn't nest. And now
you have to find all places and change them to increment/decrement a
counter and only switch the cursor when leaving/reaching 0. With RAII
you only have to adjust the constructor/destructor to fix your code.
Okay, this would also be true if you use functions to do the actual
counting/switching. But if you are not careful, you end up having some
unmatched function calls and your mouse cursor always stays like a hour
glass. This effect is impossible with RAII.


Joerg

Joshua Lehrer

unread,
May 4, 2005, 11:08:34 AM5/4/05
to

"Roshan Naik" <som...@somehwere.com> wrote in message
news:J50ee.5377$HL2....@newsread3.news.pas.earthlink.net...

> I know that using the finally block (in Java or C#) to dispose resources
is
> considered inferiror to RAII.
> However I recently came accross a little C++ example that used some
> compiler's __finally language extension
> that made me rethink there might be some value in finally...sometimes.
>
> The code was something to this effect (roughly)....
>
> mouse.setCursor(HOUR_GLASS); // change state
> try {
> doSomeTimeConsumingWork( );
> }
> __finally { // non standard extension
> mouse.setCursor(NORMAL_POINTER); //reset state
> }
>
>

I find that code much harder to follow than:

const cursort old_cursor = mouse.setCursor(HOUR_GLASS);
ON_BLOCK_EXIT_OBJ(mouse,&mouse_t::setCursor,old_cursor);

this is 2 lines, instead of 7.

You can even do it in a single line, if that floats your boat, if set
setCursor returns the old cursor:

ON_BLOCK_EXIT_OBJ(mouse,&mouse_t::setCursor,mouse.setCursor(HOUR_GLASS));

Both of these code snippets are far superior to the try/finally in
readability. Also, generally a "finally" block gets run no matter what,
even if "doSomeTimeConsumingWork" were to throw and exception. But, if an
exception were thrown, how do you know that you can reliably put the cursor
back? At least with RAII, if the exception is caught, the resource is
guaranteed to be restored (object destructor is called). If the exception
is not caught, it is undefined whether it will run, or not. On my platform,
it currently does not.


joshua lehrer
factset research systems
NYSE:FDS

david...@ed.tadpole.com

unread,
May 4, 2005, 8:01:38 PM5/4/05
to

Joshua Lehrer wrote:
<snip>

> Both of these code snippets are far superior to the try/finally in
> readability.
<snip>

This unqualified assertion makes it sound as if this is objectively
true when it is subjective. I find a finally clause far more intuitive
and readable than a side-effect of a destructor for an object defined
at the top of a (possibly lengthy) function.

Cheers,

Dave

Andrei Alexandrescu (See Website For Email)

unread,
May 4, 2005, 8:16:32 PM5/4/05
to
Roshan Naik wrote:
> I know that using the finally block (in Java or C#) to dispose resources is
> considered inferiror to RAII.
> However I recently came accross a little C++ example that used some
> compiler's __finally language extension
> that made me rethink there might be some value in finally...sometimes.
>
> The code was something to this effect (roughly)....
>
> mouse.setCursor(HOUR_GLASS); // change state
> try {
> doSomeTimeConsumingWork( );
> }
> __finally { // non standard extension
> mouse.setCursor(NORMAL_POINTER); //reset state
> }
>
>
> Clearly there is no resrouce acquisistion/disposal going on here. Just
> change some state , do some work, and then reset the state.
> And here RAII can be put to work (and ScopeGuard comes to mind), but it is
> not at all natural to use destructors for doing such things. That
> immediately feels more like a hack.... and hides the intent of the code
> somewhere behind the scenes.

The problem with the code above is that the two logically paired actions
are spread across the code. It's the exact kind of example that
ScopeGuard puts to shame, because with ScopeGuard (and ON_BLOCK_EXIT)
you can put a current and future action together, as a single unit.


Andrei

James Kanze

unread,
May 4, 2005, 8:15:32 PM5/4/05
to
Bronek Kozicki wrote:
> Roshan Naik <som...@somehwere.com> wrote:

[...]


>>Clearly there is no resrouce acquisistion/disposal going on
>>here. Just change some state , do some work, and then reset
>>the state. And here RAII can be put to work (and ScopeGuard
>>comes to mind), but it is not at all natural to use
>>destructors for doing such things.

>>That immediately feels more like a hack.... and hides the
>>intent of the code somewhere behind the scenes.

> RAII would not be hack at all, at least for me. You acquire
> resource (cursor) and then release it (reset cursor to normal
> state) when you are done.

"'Tis but thy name that is my enemy." (Romeo and Juliette,
II.2, l.38). There are no resources involved, and resource
acquision isn't being used for initialization. But what is
commonly called RAII is certainly what is called for. It sure
smells sweet, even if we don't call it a rose.

IMHO, the only reason that it feels like a hack is because the
pattern is so poorly named. I regularly use RAII for things
where no resources are involved, and just as often for cases
where the resource acquisition does not take place in the
initialization.

--
James Kanze mailto: james...@free.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Walter

unread,
May 4, 2005, 8:27:43 PM5/4/05
to

"Roshan Naik" <som...@somehwere.com> wrote in message
news:J50ee.5377$HL2....@newsread3.news.pas.earthlink.net...
> I know that using the finally block (in Java or C#) to dispose resources
is
> considered inferiror to RAII.
> However I recently came accross a little C++ example that used some
> compiler's __finally language extension
> that made me rethink there might be some value in finally...sometimes.

Using a finally block is helpful when:

1) the cleanup code needs to access local variables in the function

2) it's a one use issue; i.e. when making a class just for one use would
wind up cluttering the code

For example, suppose we want to open a file, do some processing, then make
sure it gets closed:

void foo()
{
...
FILE *fp = fopen( ... );
if (fp)
try
{
....
}
finally
{
fclose(fp);
}
}

Yes, I could wrap fp in a class with a destructor, and I would if I was
going to use it more than once. But if it's just a one shot deal, the above
is simpler and more direct. Ideally, the language should support both RAII
objects and try-finally.

James Kanze

unread,
May 5, 2005, 8:52:40 AM5/5/05
to
Walter wrote:
> "Roshan Naik" <som...@somehwere.com> wrote in message
> news:J50ee.5377$HL2....@newsread3.news.pas.earthlink.net...

>>I know that using the finally block (in Java or C#) to dispose
>>resources is considered inferiror to RAII. However I recently
>>came accross a little C++ example that used some compiler's
>>__finally language extension that made me rethink there might
>>be some value in finally...sometimes.

> Using a finally block is helpful when:

> 1) the cleanup code needs to access local variables in the function

That is (at least in my mind) one of the major motivations for
"lambda classes" (or whatever you want to call them). While
there's been a great deal of discussion concerning the possible
syntax and the various uses, I think that all of the suggestions
have in common an ability to locally define a class or a
function in which you can access local variables.

Given such a class, it's pretty trivial to define something
like:

cleanup { some code .. } ;

as a contraction for an instance of a lambda class with a
destructor consisting of the code in the {...}.

> 2) it's a one use issue; i.e. when making a class just for one
> use would wind up cluttering the code

Agreed. On the other hand, in current C++, not making the class
means duplicating the code.

IMHO, the functionality is definitly useful. The question is
just how to achieve it. Personally, I find that something like
the cleanup verb, above, fits better into the overall scheme of
things in C++.

> For example, suppose we want to open a file, do some
> processing, then make sure it gets closed:

> void foo()
> {
> ...
> FILE *fp = fopen( ... );
> if (fp)
> try
> {
> ....
> }
> finally
> {
> fclose(fp);
> }
> }

> Yes, I could wrap fp in a class with a destructor, and I would
> if I was going to use it more than once. But if it's just a
> one shot deal, the above is simpler and more direct. Ideally,
> the language should support both RAII objects and try-finally.

The problem with all such examples is that they take an obvious
and frequent case. One so obvious and frequent that it
justifies a library class to handle it. But I totally agree in
principal; there will always be one-of cases where the explicit
class is just so much verbage. On the other hand, I rather
prefer:


FILE *fp = fopen( ... ) ;

if ( fp != NULL ) {
cleanup { fclose( fp ) ; }
}

Except that it's still a bad example, since in the normal case,
I'd certainly want to handle errors in the fclose, and would
thus naturally write something along the lines of:

if ( fp != NULL ) {
try {
...
if ( fclose( fp ) != 0 ) {
// handle errors...
}
} catch ( ... ) {
fclose( fp ) ; // can't do much about errors here,
// but it doesn't matter, the
// operation is hosed anyway.
throw ;
}
}

(Except, of course, I'd actually be using fstream, so the
try/catch would be unnecessary. Unless I was outputting and
wanted to delete the corrupted file I'd just generated.)

--
James Kanze mailto: james...@free.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Roland Pibinger

unread,
May 5, 2005, 8:53:03 AM5/5/05
to
On 4 May 2005 20:16:32 -0400, "Andrei Alexandrescu (See Website For

Email)" <SeeWebsit...@moderncppdesign.com> wrote:
>
>The problem with the code above is that the two logically paired actions
>are spread across the code. It's the exact kind of example that
>ScopeGuard puts to shame, because with ScopeGuard (and ON_BLOCK_EXIT)
>you can put a current and future action together, as a single unit.

Oops! ScopeGuard/ON_BLOCK_EXIT is logically (almost) equivalent to
try/finally. The 'finally clause' is merely written before the
statements, not below. I case of ScopeGuard the user must even call a
second logically paired action (confusingly called 'dismiss'). In both
cases (try/finally and ScopeGuard) it's the user's responsibility to
set up the release of a resource. In both cases resource management is
not encapsulated.

Best regards,
Roland Pibinger

Joshua Lehrer

unread,
May 5, 2005, 12:48:10 PM5/5/05
to

<david...@ed.tadpole.com> wrote in message
news:1115224165....@o13g2000cwo.googlegroups.com...

>
> Joshua Lehrer wrote:
> <snip>
> > Both of these code snippets are far superior to the try/finally in
> > readability.
> <snip>
>
> This unqualified assertion makes it sound as if this is objectively
> true when it is subjective. I find a finally clause far more intuitive
> and readable than a side-effect of a destructor for an object defined
> at the top of a (possibly lengthy) function.
>
> Cheers,
>
> Dave
>

As you point out, in a lengthy function, try/finally puts the "undo"
operation is far away from your "do" operation. If you change your
operation at the top, you may forget that you need to scroll all the way
down to the finally block to fix the undo operation. Sure, in a SIMPLE
example such as:

do();
try {
} finally {
undo();
}

it is obvious. But, consider when there is lots of code between try and
finally. If you keep related operations next to eachother, there is less
chance that you will make a mistake later on down the road when modifying
the code.

Also, someone who looks at your code won't need to ask if you are cleaning
up your resource, as the resource is acquired and disposition is set-up on
the very next line. With try/finally one needs to scroll way down (given a
large function) to see if you are releasing the resource properly, or at
all.

joshua lehrer
factset research systems
NYSE:FDS

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Joshua Lehrer

unread,
May 5, 2005, 12:47:48 PM5/5/05
to

"Roland Pibinger" <rpb...@yahoo.com> wrote in message
news:4279ea1...@news.utanet.at...

> On 4 May 2005 20:16:32 -0400, "Andrei Alexandrescu (See Website For
> Email)" <SeeWebsit...@moderncppdesign.com> wrote:
> >
> In both
> cases (try/finally and ScopeGuard) it's the user's responsibility to
> set up the release of a resource. In both cases resource management is
> not encapsulated.
>
> Best regards,
> Roland Pibinger
>

This is correct. However, people will not take the time to write custom
classes, so, scopeguard is a compromise.

joshua lehrer
factset research systems
NYSE:FDS

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Hillel Y. Sims

unread,
May 5, 2005, 12:52:04 PM5/5/05
to

"Roland Pibinger" <rpb...@yahoo.com> wrote in message
news:4279ea1...@news.utanet.at...

> On 4 May 2005 20:16:32 -0400, "Andrei Alexandrescu (See Website
For
> Email)" <SeeWebsit...@moderncppdesign.com> wrote:
> >
> >The problem with the code above is that the two logically
paired actions
> >are spread across the code. It's the exact kind of example
that
> >ScopeGuard puts to shame, because with ScopeGuard (and
ON_BLOCK_EXIT)
> >you can put a current and future action together, as a single
unit.
>
> Oops! ScopeGuard/ON_BLOCK_EXIT is logically (almost) equivalent
to
> try/finally. The 'finally clause' is merely written before the
> statements, not below.

I have created a small extension to ScopeGuard that we have been
using locally for some time, called "finally" (the implementation
details shall be left to the imagination of the reader for the
moment). The following type of code compiles and executes
perfectly, using no non-standard language extensions. "finally"
is in extensive production use throughout our system.

using namespace boost;

mouse.setCursor(HOUR_GLASS);
finally(bind(&MouseType::setCursor, ref(mouse), NORMAL_POINTER))
{
doSomeTimeConsumingWork();
}

This provides exactly the same semantics as ON_BLOCK_EXIT, but I
like the stylistic look and feel better (esp. consistent use of
bind() to avoid the need for ON_BLOCK_EXIT vs.
ON_BLOCK_EXIT_OBJ).

I also have a similar wrapper for named ScopeGuards that can be
.Dismiss()ed, which I call GuardRegion - GuardRegion(name,
funcobj) { stuff(); name.Dismiss(); }

"Roshan Naik" <som...@somehwere.com> wrote in message
news:J50ee.5377$HL2....@newsread3.news.pas.earthlink.net...
>

> mouse.setCursor(HOUR_GLASS); // change state
> try {
> doSomeTimeConsumingWork( );
> }
> __finally { // non standard extension
> mouse.setCursor(NORMAL_POINTER); //reset state
> }
>

I feel that the RAII-based prefix form of finally() offers
benefits over this form of exception-handling - aside from
portability and potential reduction in duplication of code, there
are aspects of system debugging (in cases of abnormal termination
due to unhandled exceptions) which are often complicated by the
presence of such __finally constructs. RAII-based cleanup
handlers do not usually encounter the same difficulties. OpenVMS
(on which win32's SEH exception-handling mechanism was based) has
a similar construct called FINALLY - we have long discouraged the
use of FINALLY by developers in favor of RAII-style exception
handling, due to these issues.


--
Hillel Y. Sims
hsims AT factset.com

Joshua Lehrer

unread,
May 6, 2005, 3:53:14 AM5/6/05
to
Andrei -

I have a suggestion for a way to improve ScopeGuard and bring it's interface
more in line with boost::bind.

Using scopeguard's native object creation factories are superior to mixing
scopeguard and boost::bind because boost::bind requires dynamic memory
allocation and a virtual function call, scopeguard does not. Thus, I'd
prefer to use ScopeGuard's factory methods, rather than a mix of ScopeGuard
and boost::bind.


However, ScopeGuard strays from boost::bind in two ways:

1] boost::bind does not require special "OBJ" macros; ScopeGuard does.

2] boost::bind passes the method pointer first, then the "this" pointer,
then the arguments. ScopeGuard passes the object by reference, then the
method pointer, then the arguments by copy. This mixing of reference and
copy confuses people.


Both of these can be solved by adding additional object factory methods to
ScopeGuard.h. Here, I supply the two-argument versions, but a similar
pattern can easily be followed for the zero-argument and one-argument
versions:

template <typename Ret, typename P1, typename P2, class Obj1, class Obj2>
inline ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1,P2),P1,P2>
MakeScopeGuard(Ret(Obj2::*memFun)(P1,P2), Obj1 *obj, P1 p1, P2 p2)
{
return
ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1,P2),P1,P2>::MakeObjScopeGuard(*obj,m
emFun, p1,p2);
}

template <typename Ret, typename P1, typename P2, class Obj1, class Obj2>
inline ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1,P2)const,P1,P2>
MakeScopeGuard(Ret(Obj2::*memFun)(P1,P2)const, Obj1 *obj, P1 p1, P2 p2)
{
return
ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1,P2)const,P1,P2>::MakeObjScopeGuard(*
obj,memFun,p1,p2);
}


Usage:

old: ON_BLOCK_EXIT_OBJ(s,&string::clear);
new: ON_BLOCK_EXIT(&string::clear,&s);


Implementation details:

Two functions need to be supplied, one for const-members and one for
non-const members.

Also, these functions are templated both on the object pointer type supplied
(Obj1) AND on the method pointer's object-type (Obj2). This allows you to
pass in a pointer to a subclass, while passing in a pointer to a method on a
base. While the compiler normally would do this cast automatically, it will
not, in this case, as the other non-object templated factory methods would
be better matches without any casting, and would fail to compile.

Each factory method remains a simple cover function to creating an
ObjScopeGuardImplN. The factory method's sole purpose remains doing the
template argument deduction.


I have added these factory methods to my local version of ScopeGuard, and
thought I would share with the group.


joshua lehrer
factset research systems
NYSE:FDS

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Andrei Alexandrescu

unread,
May 6, 2005, 4:00:52 AM5/6/05
to
Hillel Y. Sims wrote:
> using namespace boost;
>
> mouse.setCursor(HOUR_GLASS);
> finally(bind(&MouseType::setCursor, ref(mouse), NORMAL_POINTER))
> {
> doSomeTimeConsumingWork();
> }
>
> This provides exactly the same semantics as ON_BLOCK_EXIT, but I
> like the stylistic look and feel better (esp. consistent use of
> bind() to avoid the need for ON_BLOCK_EXIT vs.
> ON_BLOCK_EXIT_OBJ).

That looks great, but why do you need ref(mouse) as opposed to mouse? I
think the default should be reference, and only if you need a copy you'd
say value(mouse). Or does that come with the generality of the construct?


Andrei

Hillel Y. Sims

unread,
May 6, 2005, 4:05:04 AM5/6/05
to

"James Kanze" <ka...@none.news.free.fr> wrote in message
news:4279ef04$0$315$626a...@news.free.fr...

>
>
> FILE *fp = fopen( ... ) ;
> if ( fp != NULL ) {
> cleanup { fclose( fp ) ; }
> }

What do you think about the following?

FILE* fp = fopen("xyz","r");
if (fp != 0) {
finally(bind<int>(fclose, fp)) {
process_file(fp);
}
}

I've just copy/pasted that from a source file that compiled and
linked successfully.

>
> Except that it's still a bad example, since in the normal case,
> I'd certainly want to handle errors in the fclose, and would
> thus naturally write something along the lines of:
>
> if ( fp != NULL ) {
> try {
> ...
> if ( fclose( fp ) != 0 ) {
> // handle errors...
> }
> } catch ( ... ) {
> fclose( fp ) ; // can't do much about errors
here,
> // but it doesn't matter, the
> // operation is hosed anyway.
> throw ;
> }
> }
>
> (Except, of course, I'd actually be using fstream, so the
> try/catch would be unnecessary. Unless I was outputting and
> wanted to delete the corrupted file I'd just generated.)
>

What if the filename itself has also been corrupted when you make
that call to remove(filename)? Besides, isn't fclose() a no-throw
operation?


--
Hillel Y. Sims
hsims AT factset.com

Andrei Alexandrescu

unread,
May 6, 2005, 4:05:26 AM5/6/05
to
Roland Pibinger wrote:
> On 4 May 2005 20:16:32 -0400, "Andrei Alexandrescu (See Website For
> Email)" <SeeWebsit...@moderncppdesign.com> wrote:
>
>>The problem with the code above is that the two logically paired actions
>>are spread across the code. It's the exact kind of example that
>>ScopeGuard puts to shame, because with ScopeGuard (and ON_BLOCK_EXIT)
>>you can put a current and future action together, as a single unit.
>
>
> Oops! ScopeGuard/ON_BLOCK_EXIT is logically (almost) equivalent to
> try/finally. The 'finally clause' is merely written before the
> statements, not below.

I think spreading the code gratuitously is an important detail. For
small idioms, I've noticed that things like where the logically
consistent pieces are, and what the level of syntactic baroqueness is,
do matter a lot.

> I case of ScopeGuard the user must even call a
> second logically paired action (confusingly called 'dismiss').

Nonono. "Suggestively" called dismiss. :o)

Note that try/finally doesn't have any dismissing mechanism, so it's
unfair to mention that as a disadvantage of ScopeGuard. For try/finally,
the user must maintain their own flag. (They might call it 'dismissed'.
:o)) So try/finally is more of a poor man's version of ON_BLOCK_EXIT
(with the disadvantage that it spreads away code that should be
together, but with the advantage that it allows arbitrary code in the
finally block), which in turn is a particular use of the dismissible
ScopeGuard.

> In both
> cases (try/finally and ScopeGuard) it's the user's responsibility to
> set up the release of a resource. In both cases resource management is
> not encapsulated.

It's not, but let's not forget you don't pay the price of writing the
capsule.

Would I recommend ScopeGuard instead of smart pointers? No. Would I
recommend it over writing a little class of limited utility? Yes. Would
I prefer it to try/finally even if I had the latter? Often. Use judgment
and the proper tool for the job.


Andrei

kevin cline

unread,
May 6, 2005, 6:19:25 AM5/6/05
to

Roshan Naik wrote:

Roshan Naik wrote:
> I know that using the finally block (in Java or C#) to dispose
resources is
> considered inferiror to RAII.

> However I recently came accross a little C++ example that used some
> compiler's __finally language extension
> that made me rethink there might be some value in
finally...sometimes.
>
> The code was something to this effect (roughly)....
>
> mouse.setCursor(HOUR_GLASS); // change state
> try {
> doSomeTimeConsumingWork( );
> }
> __finally { // non standard extension
> mouse.setCursor(NORMAL_POINTER); //reset state
> }
>
>
> Clearly there is no resrouce acquisistion/disposal going on here.
Just
> change some state , do some work, and then reset the state.
> And here RAII can be put to work (and ScopeGuard comes to mind), but
it is
> not at all natural to use destructors for doing such things.

It will seem perfectly natural after a bit of practice. And this sort
of thing almost never happens exactly once in an application. In your
example there are seven lines of code for controlling the cursor,
wrapped around the one line the programmer really wanted to write. How
many times are you willing to cut-and-paste those seven lines to save
writing one ten-line class? How many times are you willing to read
those seven lines on your way to finding the interesting bits that do
some time consuming work?

For me, the answer is about zero. I would create the SetWaitCursor
class immediately, because I don't want the real purpose of the code
obscured by all that noise about setting the cursor back and forth.

Andrei Alexandrescu (See Website For Email)

unread,
May 7, 2005, 7:01:31 AM5/7/05
to
Walter wrote:
> void foo()
> {
> ...
> FILE *fp = fopen( ... );
> if (fp)
> try
> {
> ....
> }
> finally
> {
> fclose(fp);
> }
> }
>
> Yes, I could wrap fp in a class with a destructor, and I would if I was
> going to use it more than once. But if it's just a one shot deal, the above
> is simpler and more direct. Ideally, the language should support both RAII
> objects and try-finally.

I think ideally, the language would support mechanisms that allow the
user to define block_cleanup code a la:

void foo()
{
...
FILE *fp = fopen( ... );

block_cleanup { fclose(fp); }
if (fp)
....
}

that is, the ability to specify code to be executed upon a scope's exit.
Refinenents would specify code to be executed upon normal or abnormal
(exceptional) leaving of the scope. (To clarify, fclose(NULL) has no
effect.)

A lot of code involving robustness in face of exceptions would be vastly
simplified using such idioms. On the other hand, it would be a pity to
burden the language proper with such syntax and semantics, so the ideal
language would embed enough growth mechanisms so as to allow things in
the block_cleanup family to be implemented as libraries.


Andrei

Roshan Naik

unread,
May 8, 2005, 1:42:29 PM5/8/05
to
> it is obvious. But, consider when there is lots of code between try and
> finally. If you keep related operations next to eachother, there is less
> chance that you will make a mistake later on down the road when modifying
> the code.

I do agree with this. Scope guard does have a downside of looking ugly and
finally block
has the problem that you mention above.

Another problem with finally is that if a exception is active when finally
block was invoked and then some operation
inside finally also throws an exception then language must decide to discard
one of the
two exceptions. Java discards the former. So thats a dirty little corner for
language designers.
I hope someday we will find a better alternative to both.


- Roshan

Seungbeom Kim

unread,
May 8, 2005, 1:35:25 PM5/8/05
to
Roland Pibinger wrote:
> On 4 May 2005 20:16:32 -0400, "Andrei Alexandrescu (See Website For
> Email)" <SeeWebsit...@moderncppdesign.com> wrote:
>
>>The problem with the code above is that the two logically paired actions
>>are spread across the code. It's the exact kind of example that
>>ScopeGuard puts to shame, because with ScopeGuard (and ON_BLOCK_EXIT)
>>you can put a current and future action together, as a single unit.
>
> Oops! ScopeGuard/ON_BLOCK_EXIT is logically (almost) equivalent to
> try/finally. The 'finally clause' is merely written before the
> statements, not below. I case of ScopeGuard the user must even call a
> second logically paired action (confusingly called 'dismiss'). In both
> cases (try/finally and ScopeGuard) it's the user's responsibility to
> set up the release of a resource. In both cases resource management is
> not encapsulated.

You call Dismiss() not to set up the release of a resource, but to
dictate that the release should be skipped, don't you? You set up some
action just in case something else fails and the control goes out of
scope, and when you see it succeeded you explicitly skip the action. I
don't agree to say that the resource management is not encapsulated in
this case; you cannot forget to release the resource.

--
Seungbeom Kim

Roshan Naik

unread,
May 8, 2005, 1:40:49 PM5/8/05
to
>> Using a finally block is helpful when:
>
>> 1) the cleanup code needs to access local variables in the function
>
> That is (at least in my mind) one of the major motivations for
> "lambda classes" (or whatever you want to call them). While
> there's been a great deal of discussion concerning the possible
> syntax and the various uses, I think that all of the suggestions
> have in common an ability to locally define a class or a
> function in which you can access local variables.

Beg to differ... but thats not a motivation for lambdas.
Using lambda instead of a finally block is like having a solution in hand
and
looking for a problem.


>
> Given such a class, it's pretty trivial to define something
> like:
>
> cleanup { some code .. } ;
>
> as a contraction for an instance of a lambda class with a
> destructor consisting of the code in the {...}.

Any reason to beleive that is more suitable than a finally block for this
task?
And lambdas are more _likely_ (i dont know the proposed semantics as of now
if there is any)
going to be more verbose than that. If its a lambda function (in future C++)
you would have to define paremater and return types...

void (void ) { some code; } // anonymous lambda function...

and if its a lambda class you would most likely need more

struct { void operator() (void) { some code;} } // anonymous lambda class

In either case you would also need to have a name if its not anonymous.

readability goes out the window... just put another try/catch inside the
"some code"
and see how readable it looks as compared to a finally block.

- Roshan

david...@ed.tadpole.com

unread,
May 8, 2005, 1:46:47 PM5/8/05
to

Joshua Lehrer wrote:
<snip>
<snip>

Ok, I doubt one of us is going to convince the other that one form is
more readable than the other. :)

I would say that your critique of try/finally is flawed. What you're
suggesting is that someone could alter the contents of a try block (I
assume putting the Do() op before the try block in your example was a
typo) and not pay attention to the rammifications of this change on the
finally block (or indeed catch blocks) that follow. Such action
strikes me as so negligent on behalf of the programmer that it's not a
compelling example of a problem with try/finally.

Cheers,

Dave

Hillel Y. Sims

unread,
May 8, 2005, 1:46:26 PM5/8/05
to

"Andrei Alexandrescu" <SeeWebsit...@moderncppdesign.com>
wrote in message news:IG12v...@beaver.cs.washington.edu...


> Hillel Y. Sims wrote:
> > using namespace boost;
> >
> > mouse.setCursor(HOUR_GLASS);
> > finally(bind(&MouseType::setCursor, ref(mouse),
NORMAL_POINTER))
> > {
> > doSomeTimeConsumingWork();
> > }
> >
> > This provides exactly the same semantics as ON_BLOCK_EXIT,
but I
> > like the stylistic look and feel better (esp. consistent use
of
> > bind() to avoid the need for ON_BLOCK_EXIT vs.
> > ON_BLOCK_EXIT_OBJ).
>
> That looks great, but why do you need ref(mouse) as opposed to
mouse? I
> think the default should be reference, and only if you need a
copy you'd
> say value(mouse). Or does that come with the generality of the
construct?
>
>


That is part of the bind() semantics -- it takes all arguments by
copy (due to issues with C++ and "forwarding constructors"); use
ref/cref wrappers to forward references. (Alternatively, a
pointer to the object (eg, "&mouse") may be passed, with the same
results.)

--
Hillel Y. Sims
hsims AT factset.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Roshan Naik

unread,
May 8, 2005, 1:49:58 PM5/8/05
to
>> Using a finally block is helpful when:
>
>> 1) the cleanup code needs to access local variables in the function
>
> That is (at least in my mind) one of the major motivations for
> "lambda classes" (or whatever you want to call them). While
> there's been a great deal of discussion concerning the possible
> syntax and the various uses, I think that all of the suggestions
> have in common an ability to locally define a class or a
> function in which you can access local variables.

Beg to differ... but thats not a motivation for lambdas.


Using lambda instead of a finally block is like having a solution in hand
and
looking for a problem.


>


> Given such a class, it's pretty trivial to define something
> like:
>
> cleanup { some code .. } ;
>
> as a contraction for an instance of a lambda class with a
> destructor consisting of the code in the {...}.

Any reason to beleive that is more suitable than a finally block for this


task?
And lambdas are more _likely_ (i dont know the proposed semantics as of now
if there is any)
going to be more verbose than that. If its a lambda function (in future C++)
you would have to define paremater and return types...

void (void ) { some code; } // anonymous lambda function...

and if its a lambda class you would most likely need more

struct { void operator() (void) { some code;} } // anonymous lambda class

In either case you would also need to have a name if its not anonymous.

readability goes out the window... just put another try/catch inside the
"some code"
and see how readable it looks as compared to a finally block.

- Roshan

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Joshua Lehrer

unread,
May 8, 2005, 1:47:08 PM5/8/05
to

"Andrei Alexandrescu" <SeeWebsit...@moderncppdesign.com> wrote in
message news:IG12v...@beaver.cs.washington.edu...
> That looks great, but why do you need ref(mouse) as opposed to mouse? I
> think the default should be reference, and only if you need a copy you'd
> say value(mouse). Or does that come with the generality of the construct?

Because all other parameters are passed by copy, and boost::bind passes the
object by copy. It is too hard to remember that yor ScopeGuard behaves in a
different way. See my post under this thread.

-josh

Andrei Alexandrescu (See Website For Email)

unread,
May 9, 2005, 2:20:17 AM5/9/05
to
david...@ed.tadpole.com wrote:
> Joshua Lehrer wrote:
[snip]

>> If you keep related operations next to eachother, there is
>
> less
>
>>chance that you will make a mistake later on down the road when
>
> modifying
>
>>the code.
>>
>>Also, someone who looks at your code won't need to ask if you are
>
> cleaning
>
>>up your resource, as the resource is acquired and disposition is
>
> set-up on
>
>>the very next line. With try/finally one needs to scroll way down
>
> (given a
>
>>large function) to see if you are releasing the resource properly, or
>
> at
>
>>all.
>
> <snip>
>
> Ok, I doubt one of us is going to convince the other that one form is
> more readable than the other. :)
>
> I would say that your critique of try/finally is flawed. What you're
> suggesting is that someone could alter the contents of a try block (I
> assume putting the Do() op before the try block in your example was a
> typo) and not pay attention to the rammifications of this change on the
> finally block (or indeed catch blocks) that follow. Such action
> strikes me as so negligent on behalf of the programmer that it's not a
> compelling example of a problem with try/finally.

Agreed, but then the same can be said about manual resource management
and many other bugs: forgetting to free() a block, fclose() a file etc.
on some execution path is negligent on behalf of the programmer and not
a problem with free() or fclose(). Indeed, it's not a problem with
those, but instead there is a problem with the underlying idiom.

I, for one, am convinced that cleanup { ... } block inserted next to the
corresponding "create mess" code is a superior idiom to which
try/finally doesn't hold a candle. In fact I am so convinced, I'm not
even deterred by the fact that it's not present in today's popular
languages. :o) Maybe in 15 years it will be common, and people will look
at weaker idioms attempting to do the same thing with the contempt they
look now at the all-declarations-at-the-top-of-each-function idiom.

In fact, at the risk of breaking my NDA, here's a fragment from the WUJ
magazine, year 2020: "Old die-hard vets still use the awkward
try/finally idiom to take care of simple function-level cleanup. This
relic of Java still shows itself up in old code that you might need to
maintain. It's officially deprecated, but now in the days of pluggable
compilers and modularly extensible languages, you can use pretty much
any language construct you want. (Besides, who cares about the standards
when Cortexsoft supports something.) In short, finally does pretty much
what cleanup { ... } does, except that it puts everything exactly in the
wrong place and adds baroque syntax on top, to the end of thoroughly
messing up the logic of the function it contaminates."


Andrei

Joshua Lehrer

unread,
May 9, 2005, 6:13:15 AM5/9/05
to

<david...@ed.tadpole.com> wrote in message
news:1115373848....@f14g2000cwb.googlegroups.com...

>
> Joshua Lehrer wrote:
> <snip>
> >
> > As you point out, in a lengthy function, try/finally puts the "undo"
> > operation is far away from your "do" operation. If you change your
> > operation at the top, you may forget that you need to scroll all the
> way
> > down to the finally block to fix the undo operation. Sure, in a
> SIMPLE
> > example such as:
> >
> > do();
> > try {
> > } finally {
> > undo();
> > }
> >
> I would say that your critique of try/finally is flawed. What you're
> suggesting is that someone could alter the contents of a try block (I
> assume putting the Do() op before the try block in your example was a
> typo) and not pay attention to the rammifications of this change on the

No. It is not a typo. You can not configure the undo() to 'finally' run,
unless you are sure that it ran successfully. The only way to do this is
start the try block AFTER you are 100% sure that do() completed succesfully
and did not throw. If "do()" were to throw, you do not want "undo()" to
run because "do()" never completed.

This is yet another example of objects being superior to try/finally. The
language guarantees that object's destructors won't get run unless the
object was constructed successfully. If you had an object:

struct doer {
doer() { do(); }
~doer() { undo(); }
};

Then you are sure that undo() will only be called if do() did not throw. If
you wrote the code with try/finally blocks, it is possible for someone to
write it incorrectly, in the way that you point out:

try {
do();
} finally {
undo();
}

In this code, if "do();" throws, "undo();" will, incorrectly, be called.


> finally block (or indeed catch blocks) that follow. Such action
> strikes me as so negligent on behalf of the programmer that it's not a
> compelling example of a problem with try/finally.
>

********
"Write code not so that it can be maintained correctly, but so that it is
harder to maintain it incorrectly."
********

By using a try/finally, you are making it too easy for a programmer to be
negligent. By using ScopeGuard, or a stack based object, you encourage
proper maintenance.

Am I negligent if I make a mistake modifying your code, when you write
spaghetti code like this:

do(1);
try {
do(2);
try {
do(3);
try {
foo();
} finally {
undo(3);
}
} finally {
undo(2);
}
} finally {
undo(1);
}

BTW, is the above code correct? Is there a nesting bug? Isn't it easier to
review the code if you see this instead:

{
do(1);
ON_BLOCK_EXIT(undo,1);

do(2);
ON_BLOCK_EXIT(undo,2);

do(3);
ON_BLOCK_EXIT(undo,3);

foo();
}


joshua lehrer
factset research systems
NYSE:FDS

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Roland Pibinger

unread,
May 9, 2005, 6:34:10 AM5/9/05
to
On 8 May 2005 13:35:25 -0400, Seungbeom Kim <musi...@bawi.org> wrote:

>Roland Pibinger wrote:
>> Oops! ScopeGuard/ON_BLOCK_EXIT is logically (almost) equivalent to
>> try/finally. The 'finally clause' is merely written before the
>> statements, not below. I case of ScopeGuard the user must even call a
>> second logically paired action (confusingly called 'dismiss'). In both
>> cases (try/finally and ScopeGuard) it's the user's responsibility to
>> set up the release of a resource. In both cases resource management is
>> not encapsulated.
>
>You call Dismiss() not to set up the release of a resource, but to
>dictate that the release should be skipped, don't you?

But 'commit()' would be a more intuitive name.

>You set up some
>action just in case something else fails and the control goes out of
>scope, and when you see it succeeded you explicitly skip the action. I
>don't agree to say that the resource management is not encapsulated in
>this case; you cannot forget to release the resource.

You (the user) must set up some action. Therefore resource management
is not encapsulated. I have yet to see a convincing example where you
have so many different resource types in a program that you cannot
afford to encapsulate each.

Best wishes,
Roland Pibinger

Dave Harris

unread,
May 9, 2005, 8:15:43 AM5/9/05
to
wal...@digitalmars.nospamm.com (Walter) wrote (abridged):

> void foo()
> {
> ...
> FILE *fp = fopen( ... );
> if (fp)
> try
> {
> ....
> }
> finally
> {
> fclose(fp);
> }
> }

I believe that particular case is already handled by:

if (boost::shared_ptr<FILE> fp( fopen( ... ), fclose )) {
// ...
}


> Using a finally block is helpful when:
>
> 1) the cleanup code needs to access local variables in the function
>
> 2) it's a one use issue; i.e. when making a class just for one use would
> wind up cluttering the code

In the example you gave, we only need one local variable, fp, and the
cleanup is already encapsulated down to a simple function call. So
something rather generic like shared_ptr is enough.

I imagine there are more complicated cases where this won't work, but I
distrust complicated code. Maybe it would be better to simplify it.

-- Dave Harris, Nottingham, UK.

ka...@gabi-soft.fr

unread,
May 9, 2005, 6:26:26 PM5/9/05
to
Roshan Naik wrote:
> >> Using a finally block is helpful when:

> >> 1) the cleanup code needs to access local variables in the
function

> > That is (at least in my mind) one of the major motivations
> > for "lambda classes" (or whatever you want to call them).
> > While there's been a great deal of discussion concerning the
> > possible syntax and the various uses, I think that all of
> > the suggestions have in common an ability to locally define
> > a class or a function in which you can access local
> > variables.

> Beg to differ... but thats not a motivation for lambdas.
> Using lambda instead of a finally block is like having a
> solution in hand and looking for a problem.

I don't see why. What you want is code that executes when the
scope ends. Creating an unnamed object (with local scope, not
temporary) whose destructor contains the code is the obvious
solution; it is, in fact, the standard C++ solution. A lambda
object just makes accessing local variables easier.

> > Given such a class, it's pretty trivial to define something
> > like:

> > cleanup { some code .. } ;

> > as a contraction for an instance of a lambda class with a
> > destructor consisting of the code in the {...}.

> Any reason to beleive that is more suitable than a finally
> block for this task?

Yes. The cleanup code is where it should be, not somewhere down
at the bottom of the block where a maintenance programmer
doesn't see it, and doesn't update it when necessary.

> And lambdas are more _likely_ (i dont know the proposed
> semantics as of now if there is any) going to be more verbose
> than that. If its a lambda function (in future C++) you would
> have to define paremater and return types...

> void (void ) { some code; } // anonymous lambda function...

> and if its a lambda class you would most likely need more

> struct { void operator() (void) { some code;} } // anonymous lambda
class

> In either case you would also need to have a name if its not
> anonymous.

There was quite a long thread about lambdas here not too long
ago. One thing was clear -- whatever the formal semantics
adopted (class or function), there was a demand that the
"frequent" uses be simple, and not too verbose. There's still
no formal proposal that I'm aware of, but I think that there is
a strong consensus that you shouldn't have to write a full class
declaration (or function definition) when all you want is a
single function and the compiler is capable of deducing the
required types.

> readability goes out the window... just put another try/catch
> inside the "some code" and see how readable it looks as
> compared to a finally block.

Just as readable as putting a try/catch block inside a finally
block, no?

--
James Kanze GABI Software


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
May 9, 2005, 6:26:05 PM5/9/05
to
Hillel Y. Sims wrote:
> "James Kanze" <ka...@none.news.free.fr> wrote in message
> news:4279ef04$0$315$626a...@news.free.fr...

> > FILE *fp = fopen( ... ) ;
> > if ( fp != NULL ) {
> > cleanup { fclose( fp ) ; }
> > }

> What do you think about the following?

> FILE* fp = fopen("xyz","r");
> if (fp != 0) {
> finally(bind<int>(fclose, fp)) {
> process_file(fp);
> }
> }

> I've just copy/pasted that from a source file that compiled
> and linked successfully.

Really? Using which compiler and which libraries? (I find it
very misleading, for example, that bind<int> can be used with a
FILE*. Supposing an appropriate finally, bind<FILE*> might not
be too bad, but I still prefer the syntax of cleanup -- a simple
inline function.)

> > Except that it's still a bad example, since in the normal
> > case, I'd certainly want to handle errors in the fclose, and
> > would thus naturally write something along the lines of:

> > if ( fp != NULL ) {
> > try {
> > ...
> > if ( fclose( fp ) != 0 ) {
> > // handle errors...
> > }
> > } catch ( ... ) {
> > fclose( fp ) ; // can't do much about errors
> here,
> > // but it doesn't matter, the
> > // operation is hosed anyway.
> > throw ;
> > }
> > }

> > (Except, of course, I'd actually be using fstream, so the
> > try/catch would be unnecessary. Unless I was outputting and
> > wanted to delete the corrupted file I'd just generated.)

> What if the filename itself has also been corrupted when you
> make that call to remove(filename)?

And why would the filename be corrupted? Anymore than anything
else, of course -- if lower level code writes through an
uninitialized pointer, there's not much you can do to protect
yourself.

> Besides, isn't fclose() a no-throw operation?

One would hope so, given that it is a C function:-). And of
course, if it wasn't, I'd be more careful about using it in a
catch block.

--
James Kanze GABI Software

Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

David Turner

unread,
May 9, 2005, 6:53:11 PM5/9/05
to
I've been following this thread for a few days, and here is my take on
the situation:

First: many things that are not obviously resources, are.
Cursor-changes included. However, it would be nice to have a
better-understood term for the set of entities bound by
initialization/cleanup contracts or pre- and postconditions. Inanouts?
;-)

Second: Finally / block cleanup / (insert variation here) is dangerous
for two essential but related reasons:

1. We're back to that age-old problem of forgetting that cleanup is
required.
2. (Perhaps controversial?) Cleanup for an entity is implied by its
initialization; a transaction making use of an entity has no business
explicitly dictating its finalization. By way of analogy, we don't
write "now switch off the stove" when writing recipes. As
initialization and cleanup are logically associated, it seems sensible
that they should be spacially associated as well, whereas code making
heavy use of "finally" tends to be afflicted with a cluttering of
concerns.

Just in case (2) isn't clear, what I'm saying is that it makes no sense
for a function making use of an object (of whatever sort) to contain
code relating to its initialization and finalization, contractual
inanout obligations, etc. These topics are presumably not the main
focus of the function. The point of a high-level language is to
abstract; to move away from the nit-picking detail required in
instructing the machine. RAII provides a rather good mechanism for
doing so; "finally" is, IMHO, a step backwards.

Regards
David Turner

ka...@gabi-soft.fr

unread,
May 10, 2005, 7:58:05 AM5/10/05
to

FWIW: I think I prefer your slightly longer name than my
"cleanup".

> Refinenents would specify code to be executed upon normal or
> abnormal (exceptional) leaving of the scope. (To clarify,
> fclose(NULL) has no effect.)

That's an interesting idea. More generally, it might be
interesting to be able to distinguish in a destructor whether it
was called normally, or because of stack unwinding. I've been
using a special function for this (commit), and most of the
time, it's not a bother, but I can think of cases where it might
be.

> A lot of code involving robustness in face of exceptions would
> be vastly simplified using such idioms. On the other hand, it
> would be a pity to burden the language proper with such syntax
> and semantics, so the ideal language would embed enough growth
> mechanisms so as to allow things in the block_cleanup family
> to be implemented as libraries.

Would be nice.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
May 10, 2005, 7:59:35 AM5/10/05
to
Roland Pibinger wrote:
> On 8 May 2005 13:35:25 -0400, Seungbeom Kim <musi...@bawi.org>
wrote:
> >Roland Pibinger wrote:
> >> Oops! ScopeGuard/ON_BLOCK_EXIT is logically (almost)
> >> equivalent to try/finally. The 'finally clause' is merely
> >> written before the statements, not below. I case of
> >> ScopeGuard the user must even call a second logically
> >> paired action (confusingly called 'dismiss'). In both cases
> >> (try/finally and ScopeGuard) it's the user's responsibility
> >> to set up the release of a resource. In both cases resource
> >> management is not encapsulated.

> >You call Dismiss() not to set up the release of a resource,
> >but to dictate that the release should be skipped, don't you?

> But 'commit()' would be a more intuitive name.

That would depend on the context, I think. But I'm not sure
"intuitive" would be the word I would choose: more usual, or
more expected, perhaps.

In the end, it is a question of view point. In Andrei's
ScopeGuard, you define finalization actions, then say dismiss to
say you don't need them. In a traditional transaction, you
carry out a number of actions, then call commit to say you want
to make them permanent.

> >You set up some action just in case something else fails and
> >the control goes out of scope, and when you see it succeeded
> >you explicitly skip the action. I don't agree to say that the
> >resource management is not encapsulated in this case; you
> >cannot forget to release the resource.

> You (the user) must set up some action. Therefore resource
> management is not encapsulated. I have yet to see a
> convincing example where you have so many different resource
> types in a program that you cannot afford to encapsulate each.

It's not a question of not being able to afford to encapsulate
each. It's more a question of handling a couple of one-of cases
easily. If you find yourself handling the same resource several
times with a ScopeGuard, then I do think you're abusing it -- if
you're doing the same thing several times, there must be an
underlying concept which needs abstracting.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Andrei Alexandrescu (See Website for Email)

unread,
May 10, 2005, 8:03:49 AM5/10/05
to
Roland Pibinger wrote:
> You (the user) must set up some action. Therefore resource management
> is not encapsulated. I have yet to see a convincing example where you
> have so many different resource types in a program that you cannot
> afford to encapsulate each.

It's hard to show you an example because obviously that would be too
large. :o) Suffice to say that Petru and I are getting praising emails
for ScopeGuard more than for any other article I've written (truth be
told, that might just as well mean that the others are terrible), and
that people I've worked long ago have consistently brought ScopeGuard
as one of their first tools whenever they moved to new companies.

Andrei

Nicola Musatti

unread,
May 10, 2005, 9:02:43 AM5/10/05
to

Roshan Naik ha scritto:

> I know that using the finally block (in Java or C#) to dispose
resources is
> considered inferiror to RAII.
> However I recently came accross a little C++ example that used some
> compiler's __finally language extension
> that made me rethink there might be some value in
finally...sometimes.
>
> The code was something to this effect (roughly)....
>
> mouse.setCursor(HOUR_GLASS); // change state
> try {
> doSomeTimeConsumingWork( );
> }
> __finally { // non standard extension
> mouse.setCursor(NORMAL_POINTER); //reset state
> }
>
>
> Clearly there is no resrouce acquisistion/disposal going on here.
Just
> change some state , do some work, and then reset the state.
> And here RAII can be put to work (and ScopeGuard comes to mind), but
it is
> not at all natural to use destructors for doing such things. That
> immediately feels more like a hack.... and hides the intent of the
code
> somewhere behind the scenes.
>
> Also it seems useful in cases where you want to guarantee the
restoration of
> an invariant.

This specific problem - setting/resetting the cursor - is a wonderful
example of how using a class is a far superior approach. If the cursor
was a local setting of your code snippet this would really boil down to
personal taste. However the cursor is a portion of the application's
global state that needs to be modified throughout the GUI subsystem.
This means that if within your doSomeTimeConsumingWork() someone else
applies your idiom the cursor would be reset too early. On the other
hand it is very easy to provide your class with a static counter which
is increased in the constructor and decreased in the destructor; the
cursor is then changed only when the counter changes from 0 to 1 and
viceversa.

>From this point it wouldn't be to difficult to modify again to keep a
static stack of cursor shapes so as to be able to handle more than to
of them.

Not only this is a problem that deserves a custom class, but it's also
one class that should be in every GUI framework.

Cheers,
Nicola Musatti

Nicola Musatti

unread,
May 10, 2005, 9:02:14 AM5/10/05
to

kevin cline ha scritto:
> Roshan Naik wrote:
[...]

> > Clearly there is no resrouce acquisistion/disposal going on here.
> Just
> > change some state , do some work, and then reset the state.
> > And here RAII can be put to work (and ScopeGuard comes to mind),
but
> it is
> > not at all natural to use destructors for doing such things.
>
> It will seem perfectly natural after a bit of practice. And this
sort
> of thing almost never happens exactly once in an application. In
your
> example there are seven lines of code for controlling the cursor,
> wrapped around the one line the programmer really wanted to write.
How
> many times are you willing to cut-and-paste those seven lines to save
> writing one ten-line class? How many times are you willing to read
> those seven lines on your way to finding the interesting bits that do
> some time consuming work?

Not only that, but as I pointed out in another message, in this case
the Copy&Paste solution doesn't work.

> For me, the answer is about zero. I would create the SetWaitCursor
> class immediately, because I don't want the real purpose of the code
> obscured by all that noise about setting the cursor back and forth.

This is an important point: the perfect candidate for RAII is an
activity that is conceptually at a lower level than the current
function.

Cheers,
Nicola Musatti

Peter Dimov

unread,
May 10, 2005, 9:00:24 AM5/10/05
to
Joshua Lehrer wrote:
> Using scopeguard's native object creation factories are superior to
> mixing scopeguard and boost::bind because boost::bind requires
> dynamic memory allocation and a virtual function call, scopeguard
> does not.

This is not strictly correct. boost::function requires dynamic memory
allocation and an indirect call. boost::bind itself does none of these. You
can use the ScopeGuard const& technique to implement

ON_BLOCK_EXIT( arbitrary-function-object );

which then allows you to use boost::bind to create the arbitrary function
object. Then you can create an alias

ON_BLOCK_EXIT_(( boost-bind-args ));

if you like. :-)

Roland Pibinger

unread,
May 10, 2005, 9:03:23 AM5/10/05
to
On 6 May 2005 04:05:26 -0400, Andrei Alexandrescu
<SeeWebsit...@moderncppdesign.com> wrote:

>Roland Pibinger wrote:
>> I case of ScopeGuard the user must even call a
>> second logically paired action (confusingly called 'dismiss').
>
>Nonono. "Suggestively" called dismiss. :o)

Recently I saw a ScopeGuard implementation that hat a commit() instead
of the dismiss(). IMO, a more intuitive name.

>> In both
>> cases (try/finally and ScopeGuard) it's the user's responsibility to
>> set up the release of a resource. In both cases resource management is
>> not encapsulated.
>
>It's not, but let's not forget you don't pay the price of writing the
>capsule.
>Would I recommend ScopeGuard instead of smart pointers? No. Would I
>recommend it over writing a little class of limited utility? Yes.

But how many different resources must be managed in a typical program
so that you cannot afford to encapsulate them? Any examples? IMO,
resource acquisition/release should always be encapsulated.

Best regards,
Roland Pibinger

Walter

unread,
May 10, 2005, 10:30:29 AM5/10/05
to

"Andrei Alexandrescu (See Website For Email)"
<SeeWebsit...@moderncppdesign.com> wrote in message
news:IG2v8...@beaver.cs.washington.edu...

> I think ideally, the language would support mechanisms that allow the
> user to define block_cleanup code a la:
>
> void foo()
> {
> ...
> FILE *fp = fopen( ... );
> block_cleanup { fclose(fp); }
> if (fp)
> ....
> }
>
> that is, the ability to specify code to be executed upon a scope's exit.

But isn't that what the finally block of try-finally does?

> Refinenents would specify code to be executed upon normal or abnormal
> (exceptional) leaving of the scope.

Having a catch can handle the exceptional leavings.

Hillel Y. Sims

unread,
May 10, 2005, 10:24:02 AM5/10/05
to

"Andrei Alexandrescu (See Website For Email)"
<SeeWebsit...@moderncppdesign.com> wrote in message
news:IG2v8...@beaver.cs.washington.edu...
>
> I think ideally, the language would support mechanisms that
allow the
> user to define block_cleanup code a la:
>
> void foo()
> {
> ...
> FILE *fp = fopen( ... );
> block_cleanup { fclose(fp); }
> if (fp)
> ....
> }
>
> that is, the ability to specify code to be executed upon a
scope's exit.

It does, and I've created some (with some help from other
libraries). I call my variation "finally":

finally.cxx (complete listing)
----------------
#include <stdio.h>
#include "scopeguard.h"
#include <boost/bind.h>
#include "finally.h" // "finally", "GuardRegion"

using namespace boost;

void process_file(FILE*) {}

int main()
{
FILE* const fp = fopen("xyz","r");


if (fp != 0) {
finally(bind<int>(fclose, fp)) {
process_file(fp);
}
}
}

---------------

<termdump>
$ build finally.cxx
- compiling FINALLY.CXX...
Compaq C++ V6.5-041 for OpenVMS Alpha V7.3-2


- linking FINALLY.EXE...
Compaq C++ CXXLINK V6.5-041


************
**
** successfully built FINALLY.EXE **
**
************
</termdump>

> Refinenents would specify code to be executed upon normal or
abnormal
> (exceptional) leaving of the scope.

I call this form "GuardRegion":

----
void DataHandler_t::fetch()
{
GuardRegion(bufguard, bind(&Buf_t::clear, ref(m_buf))) {
fetch_impl(m_buf); // dispatch to subclass (may throw)
bufguard.Dismiss();
}
}
----

>
> A lot of code involving robustness in face of exceptions would
be vastly
> simplified using such idioms.

I've been using "finally" and "GuardRegion" in production code
for about a year now, and from my experience, I completely agree!
I find them especially powerful and clean for multi-threaded
programming, with respect to dealing with pthread cancellation
exceptions (assuming an OS where it actually throws a C++
exception). Talk about rock-solid high-performance applications!

(Another nice one for multi-threading is "LockRegion", created by
Joshua Lehrer:

void App::func(const string& key)
{
shared_ptr<Obj> pobj;
LockRegion(mapMutex) {
map<string, shared_ptr<Obj> >::const_iterator p
= sharedMap.find(key);
if (p != sharedMap.end()) pobj = p->second;
}
pobj->func();
})

> so as to allow things in
> the block_cleanup family to be implemented as libraries.
>

In fact, "finally" and "GuardRegion" are completely
standard-compliant and portable, and easily built (<10 lines of
code) on top of the scopeguard library (requiring only two minor
modifications to scopeguard.. ScopeGuard::Dismiss() needs to
return the old bool value, and ScopeGuard::Execute() needs to
temporarily disable pthread-cancellation while executing the
cleanup function).

--
Hillel Y. Sims
hsims AT factset.com

FactSet Research Systems


ps:


> (To clarify, fclose(NULL) has no effect.)

I don't believe that..
http://www.opengroup.org/onlinepubs/009695399/functions/fclose.html
<quote>The fclose() function shall cause the stream pointed to by
stream to be flushed and the associated file to be
closed</quote> -- and nothing about null pointers in there..

fclose(0) returns -1 and sets EBADF status code on my system.. it
seems like undefined behavior.

david...@ed.tadpole.com

unread,
May 10, 2005, 3:39:33 PM5/10/05
to

Joshua Lehrer wrote:
> <david...@ed.tadpole.com> wrote in message
<snip>

>>>
>> I would say that your critique of try/finally is flawed. What
you're
>> suggesting is that someone could alter the contents of a try block
(I
>> assume putting the Do() op before the try block in your example was
a
>> typo) and not pay attention to the rammifications of this change on
the
>
> No. It is not a typo. You can not configure the undo() to 'finally'
run,
> unless you are sure that it ran successfully. The only way to do
this is
> start the try block AFTER you are 100% sure that do() completed
succesfully
> and did not throw. If "do()" were to throw, you do not want "undo()"
to
> run because "do()" never completed.
>
<snip>

You're absolutely right - I realised I was talking nonsense only after
I'd pressed send! I did e-mail the moderator to ask my post not to be
admitted but I guess I was a little late.

The arguments that you and Andrei have put forward certainly persuade
me that the scope guard approach has advantages over the try/finally
approach. I'll now weasle out of my original position and say that I
now find both approaches sub-optimal. If the scope guard technique was
enshrined in the standard and had some syntax to obviate the need for
ugly preprocessor macros then I'd be far more favourable towards it.

Grouping logically related operations is positive but I also like the
explicit nature of try/finally that allows the question of "what
clean-up *must* happen at the end of this function?" to be answered
with a quick scan of the code and not a check for scope-guarded objects
followed by a check on the side-effects of the relevant destructors.

Cheers,

Dave

The Sim

unread,
May 10, 2005, 5:32:19 PM5/10/05
to
<ka...@gabi-soft.fr> wrote in message
news:1115644850.0...@f14g2000cwb.googlegroups.com...

> Hillel Y. Sims wrote:
>
> > FILE* fp = fopen("xyz","r");
> > if (fp != 0) {
> > finally(bind<int>(fclose, fp)) {
> > process_file(fp);
> > }
> > }
>
> > I've just copy/pasted that from a source file that compiled
> > and linked successfully.
>
> Really? Using which compiler and which libraries?

Compaq/HP C++ V6.5 on OpenVMS (an EDG-based compiler).
boost/bind.h, a slightly modified scopeguard.h (from A.
Alexandrescu / P. Marginean), and my local library which defines
"finally".

> (I find it
> very misleading, for example, that bind<int> can be used with a
> FILE*.

fclose() is declared extern "C" and returns int. The first
template argument to bind() specifies the return type of the
function object; bind() has issues deducing the return type
automatically for extern "C" functions. bind<int> is correct in
this case.

> Supposing an appropriate finally, bind<FILE*> might not
> be too bad, but I still prefer the syntax of cleanup -- a
simple
> inline function.)
>

>


> > What if the filename itself has also been corrupted when you
> > make that call to remove(filename)?
>
> And why would the filename be corrupted? Anymore than anything
> else, of course -- if lower level code writes through an
> uninitialized pointer, there's not much you can do to protect
> yourself.

I'm a strong advocate against the use of catch(...) in almost any
form, due to the fact that assuming that it does not interfere
badly with OS-based exceptions is (at the least) not portable.
There is particularly no need for catch(...) { throw; } when
RAII-based alternatives serve the same purpose without the
platform-dependent issues.

>
> > Besides, isn't fclose() a no-throw operation?
>
> One would hope so, given that it is a C function:-). And of
> course, if it wasn't, I'd be more careful about using it in a
> catch block.
>

Sorry, I misread that part of your message.

--
Hillel Y. Sims
hsims AT factset.com
FactSet Research Systems

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Joshua Lehrer

unread,
May 10, 2005, 5:36:58 PM5/10/05
to

<ka...@gabi-soft.fr> wrote in message
news:1115644850.0...@f14g2000cwb.googlegroups.com...
> Hillel Y. Sims wrote:
> > "James Kanze" <ka...@none.news.free.fr> wrote in message
> > news:4279ef04$0$315$626a...@news.free.fr...
>
> > > FILE *fp = fopen( ... ) ;
> > > if ( fp != NULL ) {
> > > cleanup { fclose( fp ) ; }
> > > }
>
> > What do you think about the following?
>
> > FILE* fp = fopen("xyz","r");
> > if (fp != 0) {
> > finally(bind<int>(fclose, fp)) {
> > process_file(fp);
> > }
> > }
>
> > I've just copy/pasted that from a source file that compiled
> > and linked successfully.
>
> Really? Using which compiler and which libraries?

Compaq C++ V6.5 on OpenVMS with Rougewave, and an old boost port. Finally
is an internal custom macro.

> (I find it
> very misleading, for example, that bind<int> can be used with a
> FILE*. Supposing an appropriate finally, bind<FILE*> might not
> be too bad, but I still prefer the syntax of cleanup -- a simple
> inline function.)

The first template parameter to bind<> is the return type. As "fclose" is
'extern "C"', on our platform, bind can not determine the return type
automatically, so we have to supply it for bind, hence, bind<int>.

joshua lehrer
factset research systems
NYSE:FDS

The Sim

unread,
May 10, 2005, 5:33:30 PM5/10/05
to
"David Turner" <dktu...@gmail.com> wrote in message
news:1115642683.7...@o13g2000cwo.googlegroups.com...

> RAII provides a rather good mechanism for
> doing so; "finally" is, IMHO, a step backwards.


I agree with you. But what if we specify "finally" itself in
terms of RAII and generic function objects:

void fetch(OBJ*); // (eg: from some poorly-written third-party
API)
void post_fetch(OBJ*);

void myfunc(OBJ* obj)
{
finally(bind(&post_fetch, obj)) {
fetch(obj);
}
}

(the above code example is completely standard C++ and compiles
successfully on my platform)

hys


--
Hillel Y. Sims
hsims AT factset.com
FactSet Research Systems

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Jeff Flinn

unread,
May 10, 2005, 10:34:16 AM5/10/05
to

"Andrei Alexandrescu" <SeeWebsit...@moderncppdesign.com> wrote in
message news:IG12v...@beaver.cs.washington.edu...
> Hillel Y. Sims wrote:
>> using namespace boost;
>>
>> mouse.setCursor(HOUR_GLASS);
>> finally(bind(&MouseType::setCursor, ref(mouse), NORMAL_POINTER))
>> {

...

> That looks great, but why do you need ref(mouse) as opposed to mouse?

A feature of boost::bind is that the arguments are passed by value. Atleast
for me, the majority of the time, the function resulting from bind, is not
executed until the scope which call bind has been long since exited. I
rarely use boost::ref, and would hate to wrap all arguments in value(...)
calls.

Jeff Flinn

Roshan Naik

unread,
May 10, 2005, 7:59:11 PM5/10/05
to
> There was quite a long thread about lambdas here not too long
> ago. One thing was clear -- whatever the formal semantics
> adopted (class or function), there was a demand that the
> "frequent" uses be simple, and not too verbose.

That would be nice. Preferably even in the presence of templates! Would you
recall the topic of that thread ? Perhaps
I can use google groups to peruse it.

-Roshan

Peter Dimov

unread,
May 11, 2005, 3:53:56 AM5/11/05
to
ka...@gabi-soft.fr wrote:

> Hillel Y. Sims wrote:
>
>> What do you think about the following?
>
>> FILE* fp = fopen("xyz","r");
>> if (fp != 0) {
>> finally(bind<int>(fclose, fp)) {
>> process_file(fp);
>> }
>> }
>
>> I've just copy/pasted that from a source file that compiled
>> and linked successfully.
>
> Really? Using which compiler and which libraries? (I find it
> very misleading, for example, that bind<int> can be used with a
> FILE*.

The int is the return type. It's only required if the implementation of bind
can't deduce the return type of extern "C" functions, otherwise bind(
fclose, fp ) is enough.

(There is no way to portably extract the return type of an arbitrary extern
"C" function pointer in C++03.)

Andrei Alexandrescu (See Website For Email)

unread,
May 11, 2005, 6:34:16 AM5/11/05
to
Hillel Y. Sims wrote:
> "Andrei Alexandrescu (See Website For Email)"
>> (To clarify, fclose(NULL) has no effect.)

>I don't believe that..
>http://www.opengroup.org/onlinepubs/009695399/functions/fclose.html
><quote>The fclose() function shall cause the stream pointed to by
>stream to be flushed and the associated file to be
>closed</quote> -- and nothing about null pointers in there..

>fclose(0) returns -1 and sets EBADF status code on my system.. it
>seems like undefined behavior.

I knew I should check before posting... thanks for the correx.

Andrei

Andrei Alexandrescu (See Website For Email)

unread,
May 11, 2005, 7:01:25 AM5/11/05
to
david...@ed.tadpole.com wrote:
> You're absolutely right - I realised I was talking nonsense only after
> I'd pressed send! I did e-mail the moderator to ask my post not to be
> admitted but I guess I was a little late.
>
> The arguments that you and Andrei have put forward certainly persuade
> me that the scope guard approach has advantages over the try/finally
> approach.

Hey hey. In years of being on the Usenet I haven't seen this. I recall I
was chatting with a friend and we agreed that nobody on the Usenet can
convince anybody else of anything. :o) Congratulations!

> Grouping logically related operations is positive but I also like the
> explicit nature of try/finally that allows the question of "what
> clean-up *must* happen at the end of this function?" to be answered
> with a quick scan of the code and not a check for scope-guarded objects
> followed by a check on the side-effects of the relevant destructors.

Now here's an interesting thing. As I've said in another post (the
example with the database and the in-memory cache) guards are often
sprinkled through a function, and not concentrated in one point. This is
because certain actions of a function must be undone upon the rest of
the function failing; not all, and not lumped together.


Andrei

Andrei Alexandrescu (See Website For Email)

unread,
May 11, 2005, 7:11:12 AM5/11/05
to
Walter wrote:
> "Andrei Alexandrescu (See Website For Email)"
> <SeeWebsit...@moderncppdesign.com> wrote in message
> news:IG2v8...@beaver.cs.washington.edu...
>
>>I think ideally, the language would support mechanisms that allow the
>>user to define block_cleanup code a la:
>>
>>void foo()
>>{
>> ...
>> FILE *fp = fopen( ... );
>> block_cleanup { fclose(fp); }
>> if (fp)
>> ....
>>}
>>
>>that is, the ability to specify code to be executed upon a scope's exit.
>
>
> But isn't that what the finally block of try-finally does?

Ah, I meant, "the ability to specify, at any point inside a scope, code
to be executed upon that scope's exit".

>>Refinenents would specify code to be executed upon normal or abnormal
>>(exceptional) leaving of the scope.
>
> Having a catch can handle the exceptional leavings.

Well modulo the known problems of the catch with ellipsis. :o}

There's a thing about try/catch that this thread made me understand. The
common view is that try/catch allows you to focus on the main logic of
the function and on the error conditions in separate places etc. But you
still have a scope and a level of indentation there for the try part
(IMHO indentation adds intellectual overhead). Besides, the places in
which you actually do work in the catch block that is related to the
error itself are only a few in an application (centralized error
handling, right?) Most of the time, you just want to take contingency
measures to cover your *own*, um, traces. So what you really want in a
function that has multiple failure point is, "if things succeeeded up to
this point and something bad happens later, I'd need this action to be
executed". try's and catch's and finally's allow that, but not in a
simple and direct way.


Andrei

Andrei Alexandrescu (See Website For Email)

unread,
May 11, 2005, 7:09:39 AM5/11/05
to
David Turner wrote:
> Just in case (2) isn't clear, what I'm saying is that it makes no sense
> for a function making use of an object (of whatever sort) to contain
> code relating to its initialization and finalization, contractual
> inanout obligations, etc. These topics are presumably not the main
> focus of the function. The point of a high-level language is to
> abstract; to move away from the nit-picking detail required in
> instructing the machine. RAII provides a rather good mechanism for
> doing so; "finally" is, IMHO, a step backwards.

That's true, however there's more about it than that. Focusing on
resources only catches part of the story. It's not about resources as
much as about the basics of doing and undoing actions.

The example I give in my talk on ScopeGuard is a simple function that
adds a record to a database, and to the in-memory cache of the database.
The function has two failure points as both actions might fail. While
considering an entry in a vector a resource and writing a class
PopBacker to dispose of it works, it is a stretch. You care about
removing an entry from the vector if the database action fails, and an
implementation based on ScopeGuard is shorter and arguably easier to
understand than other approaches.

Furthermore, ScopeGuard scales up. In a function with N failure points
there is no increase in indentation and a linear blowup in size for
planting the appropriate guards. Defining a little class for each undo
of an action is a linear blowup, but of much larger proportions, and
scatters stuff all over the place (classes with awkward names such as
VectorAppender and DatabaseRowAdder and CounterIncrementer, oh joy!),
some of which might be reusable (if you care to sift through the wads of
code or documentation), and most of which isn't. Doing it in-situ with
try blocks is a linear blowup in level of indentation, which I see as bad.

That's why I'm thinking - a language feature that does what ScopeGuard
does but with access to local state would be way more useful and used
than the awkward try blocks.

I see our community slowly moving towards better idioms for handling
errors. The global "errno" - can you believe that was cool at some
point? :o) - and error flags and HRESULT and singular values returned
are but an awkward first step. Then, try/catch/finally blocks are the
second. IMHO cleanup { ... } blocks would be the third. Heck, I'm
starting to talk Hegelian dialectics around here :o).


Andrei

Andrei Alexandrescu (See Website For Email)

unread,
May 11, 2005, 7:08:11 AM5/11/05
to
Hillel Y. Sims wrote:
> It does, and I've created some (with some help from other
> libraries). I call my variation "finally":
>
> finally.cxx (complete listing)
> ----------------
> #include <stdio.h>
> #include "scopeguard.h"
> #include <boost/bind.h>
> #include "finally.h" // "finally", "GuardRegion"
>
> using namespace boost;
>
> void process_file(FILE*) {}
>
> int main()
> {
> FILE* const fp = fopen("xyz","r");
> if (fp != 0) {
> finally(bind<int>(fclose, fp)) {
> process_file(fp);
> }
> }
> }

[snipoletto]

> I've been using "finally" and "GuardRegion" in production code
> for about a year now, and from my experience, I completely agree!
> I find them especially powerful and clean for multi-threaded
> programming, with respect to dealing with pthread cancellation
> exceptions (assuming an OS where it actually throws a C++
> exception). Talk about rock-solid high-performance applications!

Given that you took time to tantalize this group with your and Joshua's
code, I suggest you guys to make it public someplace (maybe even submit
to boost) and let me know; I'll link to it from the website with the
ScopeGuard article.


Andrei

Andrei Alexandrescu (See Website For Email)

unread,
May 11, 2005, 7:14:29 AM5/11/05
to
Roland Pibinger wrote:
> On 6 May 2005 04:05:26 -0400, Andrei Alexandrescu
> <SeeWebsit...@moderncppdesign.com> wrote:
>
>>Roland Pibinger wrote:
>>
>>>I case of ScopeGuard the user must even call a
>>>second logically paired action (confusingly called 'dismiss').
>>
>>Nonono. "Suggestively" called dismiss. :o)
>
>
> Recently I saw a ScopeGuard implementation that hat a commit() instead
> of the dismiss(). IMO, a more intuitive name.

I see. It's compelling, but I'm not convinced just yet. This is because
"commit" suggest that work has been done on the side and now it is being
committed. That's not a very accurate description of the ScopeGuard's
functioning, which is, "ScopeGuard will take the measures you specify
unless you call this function".

Andrei

David Turner

unread,
May 11, 2005, 7:53:42 AM5/11/05
to
"The Sim" wrote...

> void fetch(OBJ*); // (eg: from some poorly-written third-party
> API)
> void post_fetch(OBJ*);
>
> void myfunc(OBJ* obj)
> {
> finally(bind(&post_fetch, obj)) {
> fetch(obj);
> }
>
> }

I'd still be far more comfortable encapsulating that usage in a class;
as others have pointed out, this future-proofs you against possible API
changes or discovering a bug in the above usage. It's also simpler to
use and can provide more clarity, as:

class WithFetchedOBJ {
OBJ* obj_;
public:
WithFetchedOBJ(OBJ* obj): obj_(obj) { fetch(obj_); }
~WithFetchedOBJ() { post_fetch(obj_); }
};

void myfunc(OBJ* obj) {
WithFetchedOBJ o(obj); // contrast with finally(bind(...))
// ...
}

Regards
David Turner

"Daniel Krügler (ne Spangenberg)"

unread,
May 11, 2005, 7:42:24 AM5/11/05
to
Hello Hillel Y. Sims,

The Sim schrieb:

>I'm a strong advocate against the use of catch(...) in almost any
>form, due to the fact that assuming that it does not interfere
>badly with OS-based exceptions is (at the least) not portable.
>

I can't follow your reasoning. Why should it **not** be portable,
assuming, that it does **not**
interfere with OS-based exceptions?

>There is particularly no need for catch(...) { throw; } when
>RAII-based alternatives serve the same purpose without the
>platform-dependent issues.
>

RAII is no useful replacement in case of one general exception handler,
like this

void general_exception_handler() {
try {
throw;
}
catch(const E1& e) {
..
}
catch(const E2& e) {
..
}
...
catch(...) {
...
}
}

void bar();

void foo() {
try {
bar();
}
catch(...) {
general_exception_handler();
}
}

This idiom is useful in operations near to the UI-layer where concrete
representation of exception reasons is needed. Yes, it does not work well
for compilers mixing OS-exceptions with language-exceptions (e.g. the
MS family of compilers), but actually it is a nice idea and see no reason
for non-portability.

Greetings from Bremen,

Daniel Krügler

Joshua Lehrer

unread,
May 11, 2005, 7:55:33 AM5/11/05
to

<david...@ed.tadpole.com> wrote in message
news:1115660223.0...@z14g2000cwz.googlegroups.com...

> If the scope guard technique was
> enshrined in the standard and had some syntax to obviate the need for
> ugly preprocessor macros then I'd be far more favourable towards it.

ScopeGuard requires no preprocessor macros:

ScopeGuard guard = MakeScopeGuard(printf,"goodbye %s",name);

If you want the convenience of not having to name your variables, then there
is a single macro to wrap that up which is something like:

#define ON_BLOCK_EXIT ScopeGuard CONCAT(RandomeGuardName,__LINE__) =
MakeScopeGuard

that's it. To what ugly preprocessor macros were you referring?

There is no reason to make it part of the language unless it requires
language changes. ScopeGuard works, just fine, as it is now. We may want
to consider placing it into the standard library, which would give it an
official blessing, but it requires no language changes.

Now, if only we could convert the rest of you... :)

joshua lehrer
factset research systems
NYSE:FDS

ka...@gabi-soft.fr

unread,
May 12, 2005, 3:06:35 AM5/12/05
to
The Sim wrote:
> <ka...@gabi-soft.fr> wrote in message
> news:1115644850.0...@f14g2000cwb.googlegroups.com...
> > Hillel Y. Sims wrote:

> > > FILE* fp = fopen("xyz","r");
> > > if (fp != 0) {
> > > finally(bind<int>(fclose, fp)) {
> > > process_file(fp);
> > > }
> > > }

> > > I've just copy/pasted that from a source file that compiled
> > > and linked successfully.

> > Really? Using which compiler and which libraries?

> Compaq/HP C++ V6.5 on OpenVMS (an EDG-based compiler).
> boost/bind.h, a slightly modified scopeguard.h (from A.
> Alexandrescu / P. Marginean), and my local library which
> defines "finally".

Which of course means that I can't compile it:-). (Of course,
you didn't claim otherwise.)

> > (I find it very misleading, for example, that bind<int> can
> > be used with a FILE*.

> fclose() is declared extern "C" and returns int. The first
> template argument to bind() specifies the return type of the
> function object; bind() has issues deducing the return type
> automatically for extern "C" functions. bind<int> is correct
> in this case.

My mistake, of course. I was seeing the int as the parameter
type, although it's obvious that that can be deduced.

> > Supposing an appropriate finally, bind<FILE*> might not be
> > too bad, but I still prefer the syntax of cleanup -- a
> > simple inline function.)

> > > What if the filename itself has also been corrupted when
> > > you make that call to remove(filename)?

> > And why would the filename be corrupted? Anymore than
> > anything else, of course -- if lower level code writes
> > through an uninitialized pointer, there's not much you can
> > do to protect yourself.

> I'm a strong advocate against the use of catch(...) in almost
> any form, due to the fact that assuming that it does not
> interfere badly with OS-based exceptions is (at the least) not
> portable.

The semantics of catch(...) are specified by the standard. You
should be able to count on them. (But then, you should also be
able to count on the presence of export.) I've never had any
problem with it, but then, I've never used a compiler which
mixed up system traps (which generate signals everywhere I've
worked) and exceptions. (On the other hand, I still have to
deal with compilers which can't handle the templates in Boost --
I haven't gotten up the courage to try Loki on them.)

Of course, in this particular case, I actually have a class
which removes a file in its destructor (two, in fact -- one
which supports commit, and one which doesn't). So of course, I
would use of of them, rather than catch(...) or finally, or any
new mechanism which came along.

> There is particularly no need for catch(...) { throw; } when
> RAII-based alternatives serve the same purpose without the
> platform-dependent issues.

RAII-based mechanisms are (presently) somewhat heavy when the
clean up code needs access to local variable. Boost::bind
solves this somewhat (although the complexities are still there,
under the hood), but limits you to a single function (I think).
IMHO, the is a great advantage in putting the cleanup code next
to what needs cleaning up, but I'd like to see more language
level support for it.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Joshua Lehrer

unread,
May 12, 2005, 3:22:23 AM5/12/05
to
"David Turner" <dktu...@gmail.com> wrote in message
news:1115796903.4...@z14g2000cwz.googlegroups.com...

> "The Sim" wrote...
>
> > void fetch(OBJ*); // (eg: from some poorly-written third-party
> > API)
> > void post_fetch(OBJ*);
> >
> > void myfunc(OBJ* obj)
> > {
> > finally(bind(&post_fetch, obj)) {
> > fetch(obj);
> > }
> >
> > }
>
> I'd still be far more comfortable encapsulating that usage in a class;
> as others have pointed out, this future-proofs you against possible API
> changes or discovering a bug in the above usage. It's also simpler to
> use and can provide more clarity, as:
>

It's almost always nicer to encapsulate in a class. I'll repost a quote
from Andrei:

"Solutions that require a lot of discipline and grunt work are not very
attractive. Under schedule pressure, a good but clumsy solution loses its
utility. Everybody knows how things must be done by the book, but will
consistently take the shortcut. The one true way is to provide reusable
solutions that are correct and easy to use." - Andrei Alexandrescu

ScopeGuard solves that problem. Give them a tool which is easy to use and
solves the problem. Sure, a class may be better in most cases, but
scopeguard is just as good, and people will use it, even during crunch time.

joshua lehrer
factset research systems
NYSE:FDS

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

ka...@gabi-soft.fr

unread,
May 12, 2005, 3:08:03 AM5/12/05
to

Normally, for this sort of thing, the action which modifies the
cursor returns the previous value. So there is no need for any
special logic -- *you* set the cursor to an hourglass (or
whatever) when you start, and you, via your RAII class, restores
it to whatever it was before.

The procedure nests naturally. If somewhere in the code you
call someone sets the cursor to an hourglass, they will restore
it to whatever it was before -- when you called this function,
to an hourglass.

In the end, there's no difference between this and how you
handle the formatting flags in a stream -- anytime you modify a
formatting flag, you save the previous value, and restore it,
without worrying about what it might actually have been.

> From this point it wouldn't be to difficult to modify again to
> keep a static stack of cursor shapes so as to be able to
> handle more than to of them.

You already have a stack. The call stack on which local
variables are created. You don't need another one.

(Actually, in the case of a cursor, you might. If, for example,
the job is long enough that you spawn a worker thread to do it
in, and return immediately, so that the GUI remains reactive.
But of course, in such cases, RAII doesn't work either.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Roshan Naik

unread,
May 12, 2005, 3:15:52 AM5/12/05
to
> #define ON_BLOCK_EXIT ScopeGuard CONCAT(RandomeGuardName,__LINE__) =
> MakeScopeGuard
>
> that's it. To what ugly preprocessor macros were you referring?
>
> There is no reason to make it part of the language unless it requires
> language changes. ScopeGuard works, just fine, as it is now. We may want
> to consider placing it into the standard library, which would give it an
> official blessing, but it requires no language changes.
>
> Now, if only we could convert the rest of you... :)

IMHO, such a broadly useful thing definitely belongs in the standard (after
thorough review). It has the benefit that most book authors will write about
it and people wont have to flock to newsgroups to know such fundamental
stuff. ScopeGuard type of factility in particular, perhaps should be learnt
in conjunction with try/catch. Learing this early is better than late.
Information obtained from newsgroups and attending talks and magazines only
caters to a minuscule fraction of the worldwide C++ population.

Also agree that RAII is perhaps a quirky name... it is more general to think
of the problem as do/undo action...instead of in terms of resource
acquisition/releasing.
A language level construct that supports side by side specification of undo
actions, seems interesting atleast at first sight...instead of having to
rely in destructors behind the scenes.

-Roshan

ka...@gabi-soft.fr

unread,
May 12, 2005, 3:09:36 AM5/12/05
to
Roshan Naik wrote:
> > There was quite a long thread about lambdas here not too long
> > ago. One thing was clear -- whatever the formal semantics
> > adopted (class or function), there was a demand that the
> > "frequent" uses be simple, and not too verbose.

> That would be nice. Preferably even in the presence of
> templates! Would you recall the topic of that thread ? Perhaps
> I can use google groups to peruse it.

I don't remember the subject line, but I think if you do a
search in this group for lambda, maybe limiting the search to
the last year, you'll probably find it.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Roshan Naik

unread,
May 12, 2005, 3:18:20 AM5/12/05
to
>> > That is (at least in my mind) one of the major motivations
>> > for "lambda classes" (or whatever you want to call them).
>> > While there's been a great deal of discussion concerning the
>> > possible syntax and the various uses, I think that all of
>> > the suggestions have in common an ability to locally define
>> > a class or a function in which you can access local
>> > variables.
>
>> Beg to differ... but thats not a motivation for lambdas.
>> Using lambda instead of a finally block is like having a
>> solution in hand and looking for a problem.
>
> I don't see why. What you want is code that executes when the
> scope ends. Creating an unnamed object (with local scope, not
> temporary) whose destructor contains the code is the obvious
> solution; it is, in fact, the standard C++ solution. A lambda
> object just makes accessing local variables easier.
>

It is a possible application of lambdas... but that is different from being
a major motivation for having it.

-Roshan

Joshua Lehrer

unread,
May 12, 2005, 3:26:33 AM5/12/05
to

"Andrei Alexandrescu (See Website For Email)"
<SeeWebsit...@moderncppdesign.com> wrote in message
news:IGAK1...@beaver.cs.washington.edu...

> Given that you took time to tantalize this group with your and Joshua's
> code, I suggest you guys to make it public someplace (maybe even submit
> to boost) and let me know; I'll link to it from the website with the
> ScopeGuard article.
>
>
> Andrei
>

Ok. I've already posted and emailed you my code improvement to scopeguard,
specifically, the better overload of the create functions so you don't need
the Obj versions.

Hillel can post his 'finally' and 'GuardRegion' macros.


Here is my LockRegion code. It uses a technique similar to ScopeGuard in
order to 'lock' and 'unlock' an object. It can lock and unlock anything, as
long as the object has methods of those names. It can be used from
templated code, for example, to lock/unlock a real lock, or a null lock,
etc... It basically converts any object with lock/unlock to RAII, and
creates a scope/region at the same time.

Usage:

LockRegion(g_mx) {
// g_mx, whatever that is, is 'lock'ed in this scope, and 'unlock'ed
outside
}

If people copy this for there own code, or publish this elsewhere, it would
be nice if you could give credit where credit is due.

First, we use a base class that most of our region-style guards inherit
from. This way, the class can be tested inside of an "if" statement. It
resolves to false so that the else clause gets run:

Header "region_guard.h":

struct region_guard {
operator const void*() const { return 0; }
};


Header "lock_region.h":

//this is the macro that you use in your code:
#define LockRegion(x) if (const region_guard &LockRegionObfuscatedName =
make_lock_region(x)) { throw; } else

//templated implementation class, contains reference to an object
//calls 'lock' in contstructor, 'unlock' in destructor
//m_enabled boolan is used to transfer ownership of return value
//of make_lock_region (see below)
template <typename T>
struct LockRegionImpl : public region_guard {
LockRegionImpl(T& mx) : m_mx(mx), m_enabled(true) {
mx.lock();
}
LockRegionImpl(const LockRegionImpl<T> &rhs) : m_mx(rhs.m_mx),
m_enabled(rhs.m_enabled) {
rhs.m_enabled=false;
}
~LockRegionImpl() {
if (m_enabled) m_mx.unlock();
}
private:
T& m_mx;
mutable bool m_enabled;
};

//templated constructor function, like std::make_pair
template <typename T>
inline LockRegionImpl<T> make_lock_region(T& mx) {
return LockRegionImpl<T>(mx);
}


joshua lehrer
factset research systems
NYSE:FDS

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Andrei Alexandrescu (See Website For Email)

unread,
May 12, 2005, 3:24:10 AM5/12/05
to
David Turner wrote:
> I'd still be far more comfortable encapsulating that usage in a class;
> as others have pointed out, this future-proofs you against possible API
> changes or discovering a bug in the above usage. It's also simpler to
> use and can provide more clarity, as:
>
> class WithFetchedOBJ {
> OBJ* obj_;
> public:
> WithFetchedOBJ(OBJ* obj): obj_(obj) { fetch(obj_); }
> ~WithFetchedOBJ() { post_fetch(obj_); }
> };
>
> void myfunc(OBJ* obj) {
> WithFetchedOBJ o(obj); // contrast with finally(bind(...))
> // ...
> }

The awkward name is already a name that something doesn't map
conceptually well around here.

Andrei

Gerhard Menzl

unread,
May 12, 2005, 3:37:51 AM5/12/05
to
Andrei Alexandrescu (See Website For Email) wrote:

> Furthermore, ScopeGuard scales up. In a function with N failure points
> there is no increase in indentation and a linear blowup in size for
> planting the appropriate guards. Defining a little class for each undo
> of an action is a linear blowup, but of much larger proportions, and
> scatters stuff all over the place (classes with awkward names such as
> VectorAppender and DatabaseRowAdder and CounterIncrementer, oh joy!),
> some of which might be reusable (if you care to sift through the wads
> of code or documentation), and most of which isn't. Doing it in-situ
> with try blocks is a linear blowup in level of indentation, which I
> see as bad.

Sounds like ScopeGuard is to RAII classes as lambdas are to functors.


--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

The Sim

unread,
May 12, 2005, 4:34:12 AM5/12/05
to
"David Turner" <dktu...@gmail.com> wrote in message
news:1115796903.4...@z14g2000cwz.googlegroups.com...

> "The Sim" wrote...
>
> > void fetch(OBJ*); // (eg: from some poorly-written
third-party
> > API)
> > void post_fetch(OBJ*);
> >
> > void myfunc(OBJ* obj)
> > {
> > finally(bind(&post_fetch, obj)) {
> > fetch(obj);
> > }
> >
> > }
>
> I'd still be far more comfortable encapsulating that usage in a
class;
> as others have pointed out, this future-proofs you against
possible API
> changes or discovering a bug in the above usage. It's also
simpler to
> use and can provide more clarity, as:
>
> class WithFetchedOBJ {
> OBJ* obj_;
> public:
> WithFetchedOBJ(OBJ* obj): obj_(obj) { fetch(obj_); }
> ~WithFetchedOBJ() { post_fetch(obj_); }
> };
>
> void myfunc(OBJ* obj) {
> WithFetchedOBJ o(obj); // contrast with finally(bind(...))
> // ...
> }
>

RAII encapsulation may indeed generally improve clarity at the
end-user point inside myfunc().. but for the kind of ad-hoc
situation such as above, I have several thoughts about this:
#1) How does this future-proof the code? Assuming that
"WithFetchedOBJ" in this case is probably a local helper type
anyhow, the application code will need to change to respect the
new API behavior in either form.
#2) Since the helper RAII class will be a local "one-off" type,
it does not really save any coding nor help prevent bugs in the
API usage.

--
Hillel Y. Sims
hsims AT factset.com
FactSet Research Systems

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

The Sim

unread,
May 12, 2005, 4:36:20 AM5/12/05
to
"Daniel Krügler (ne Spangenberg)" <d...@bdal.de> wrote in message
news:4281c24c$0$305$4d4e...@businessnews.de.uu.net...

> Hello Hillel Y. Sims,
>
> The Sim schrieb:
>
> >I'm a strong advocate against the use of catch(...) in almost
any
> >form, due to the fact that assuming that it does not interfere
> >badly with OS-based exceptions is (at the least) not portable.
> >
> I can't follow your reasoning. Why should it **not** be
portable,
> assuming, that it does **not**
> interfere with OS-based exceptions?

This behavior is permitted by the C++ Standard (OS exceptions
could be represented by C++ exceptions with secret typenames that
user code cannot catch directly). For example, on the VMS
operating system which I generally use, OS exceptions may be
intercepted by catch(...). This is also the case on Windows
(although there is a hack/workaround for that, but it is not
clear whether it is 100% reliable).


Hello Daniel. It is highly unlikely, in my experience, to
(actually) need to handle more than one or two categories of
exceptions types at any given scope when appropriate exception
hierarchies are being used (wherein all exception objects across
the application and all libraries are inherited from some subtype
of std::exception). In the case of "I want to handle various
specific exception subtypes", this is then simply handled via:

void foo()
{
try {
bar();
}
catch (runtime_error&) {
runtime_error_general_exception_handler();
}
}

Where "runtime_error_general_exception_handler()" can then do the
"try { throw; } catch(DiskError&) { .. } catch (SocketError&) {
.. }" etc. trick -- *BUT* it only needs to catch specific
subtypes of the base exception.

In fact, even for the further claim "But I really must catch any
type of exception that was thrown" (in which case it is probably
a bad idea to handle them all as separate types within the same
exception_handler function), it is then *still* possible to rely
on catch(std::exception&) to catch all C++ exceptions for the
exception-redirector catch block. There is no need to intercept
"(...)", and thereby OS exceptions can be avoided.

--
Hillel Y. Sims
hsims AT factset.com
FactSet Research Systems

David Turner

unread,
May 12, 2005, 7:43:12 AM5/12/05
to
> #1) How does this future-proof the code? Assuming that
> "WithFetchedOBJ" in this case is probably a local helper type
> anyhow, the application code will need to change to respect the
> new API behavior in either form.

That goes without saying. However (1) in the case of the API being
encapsulated in a class, the changes are *localized*, which tends to
make your life easier; (2) when you need to change the logic for
acquiring/releasing OBJs, you can do this without touching the logic
for actually using them, which may save a bug or two; and conversely
(3) when you need to modify the control logic in myfunc(), you can do
this without getting conceptually involved in the process of
acquiring/releasing OBJs, which certainly makes your life as a
programmer easier.


> #2) Since the helper RAII class will be a local "one-off" type,
> it does not really save any coding nor help prevent bugs in the
> API usage.

"One-off" never is :-). But even if it were, RAII encapsulation
requires only slightly more code and provides a cleaner conceptual
separation. By concentrating on (ideally) one idea at a time, you are
better able to ensure that your program is correct. This is one of the
cornerstones of computer science: divide and conquer. Or at any rate,
it was the first fundamental idea in CS I ever learned :-).

Regards
David Turner

David Turner

unread,
May 12, 2005, 9:19:53 AM5/12/05
to
> The example I give in my talk on ScopeGuard is a simple function that
> adds a record to a database, and to the in-memory cache of the
database.
> The function has two failure points as both actions might fail. While
> considering an entry in a vector a resource and writing a class
> PopBacker to dispose of it works, it is a stretch. You care about
> removing an entry from the vector if the database action fails, and
an
> implementation based on ScopeGuard is shorter and arguably easier to
> understand than other approaches.

I agree that that's a good example (certainly better than the others
I've seen posted so far) of when ScopeGuard can be fruitfully applied.
However, my reason for saying so is that in this case the rollback
action is conceptually linked to the purpose of the function, rather
than being an essential property of an adjunct object.

ScopeGuard is certainly a useful concept. My beef is not with your
idea, Andrei, but with what appears to me to be a general lack of
insight "out there" as to why RAII is so important relative to
"finally". As I intimated in another post, the why can be summarized
in three words, as "divide and conquer". Things that are conceptually
related should be spacially related in the code.

This is something I believe every programmer should know instinctively,
yet I still see highly respected and senior programmers churning out
page-long functions, containing a clutter of unrelated ideas and
concepts, with nary a blush.

But perhaps I'm just an ontological nit-picker :-).

Regards
David Turner

Martin Eisenberg

unread,
May 12, 2005, 10:30:16 AM5/12/05
to
Andrei Alexandrescu (See Website For Email) wrote:

> Roland Pibinger wrote:

>> Recently I saw a ScopeGuard implementation that hat a commit()
>> instead of the dismiss(). IMO, a more intuitive name.
>
> I see. It's compelling, but I'm not convinced just yet. This is
> because "commit" suggest that work has been done on the side and
> now it is being committed. That's not a very accurate
> description of the ScopeGuard's functioning, which is,
> "ScopeGuard will take the measures you specify unless you call
> this function".

On a high enough level not undoing your actions is the same as
commiting to them. Why not choose the interface from that viewpoint?
To the implementer dismiss() certainly does what it says but I find
it something of a double negation. But then, double negation often
connotes irony which wouldn't come unexpectedly from you.


Martin

--
Quidquid latine dictum sit, altum viditur.

The Sim

unread,
May 12, 2005, 10:31:25 AM5/12/05
to
"David Turner" <dktu...@gmail.com> wrote in message
news:1115895404....@g43g2000cwa.googlegroups.com...

>
> That goes without saying. However (1) in the case of the API
being
> encapsulated in a class, the changes are *localized*, which
tends to
> make your life easier; (2) when you need to change the logic
for
> acquiring/releasing OBJs, you can do this without touching the
logic
> for actually using them, which may save a bug or two; and
conversely
> (3) when you need to modify the control logic in myfunc(), you
can do
> this without getting conceptually involved in the process of
> acquiring/releasing OBJs, which certainly makes your life as a
> programmer easier.
>
>

Here's another situation where ScopeGuard/finally() can be very
useful - it's not just useful for "cleanup" in the customary
sense of releasing resources, but can also be used for modelling
state transitions upon exiting scopes, eg:

void obj::handle_command(...)
{
State nextstate = ERROR;
finally(bind(&obj::set_state, this, cref(nextstate))) {
complicated_stuff(...); // may throw
for (unsigned i = 0; i < something; ++i) {
some_other_stuff(...); // may throw
}
nextstate = READY;
}
}

("finally()" code coming soon)

--
Hillel Y. Sims
hsims AT factset.com
FactSet Research Systems

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Nicola Musatti

unread,
May 12, 2005, 10:29:53 AM5/12/05
to

David Turner ha scritto:
[...]

> This is something I believe every programmer should know
instinctively,
> yet I still see highly respected and senior programmers churning out
> page-long functions, containing a clutter of unrelated ideas and
> concepts, with nary a blush.

Unfortunately being good at programming, in the sense of being able to
implement many function points or features per time unit, doesn't
necessarily imply being good at designing programs, in the sense of
being able to reasonably identify abstractions and to produce code that
reflects such separation.

In my opinion one of the keys to quality software design is being able
to recognize that two "things" are actually the same and to use the
tools supplied by the programming language to implement a single
representation of that "thing".

Incidentally this is one of the main reasons why I prefer to program in
C++: it provides more tools to do it than most of the languages I'm
aware of.

Cheers,
Nicola Musatti

Roland Pibinger

unread,
May 13, 2005, 5:14:30 AM5/13/05
to
On 11 May 2005 07:09:39 -0400, "Andrei Alexandrescu (See Website For
Email)" <SeeWebsit...@moderncppdesign.com> wrote:

>The example I give in my talk on ScopeGuard is a simple function that
>adds a record to a database, and to the in-memory cache of the database.
>The function has two failure points as both actions might fail. While
>considering an entry in a vector a resource and writing a class
>PopBacker to dispose of it works, it is a stretch. You care about
>removing an entry from the vector if the database action fails, and an
>implementation based on ScopeGuard is shorter and arguably easier to
>understand than other approaches.

Hmm,

void SomeClass::foo() throw (DBException) {
// ...
recordCache.tryInsert (pRecord);
insertIntoDB (pRecord);
recordCache.commitInsert (pRecord);
}

No ScopeGuard and no try/catch.

Best regards,
Roland Pibinger

The Sim

unread,
May 13, 2005, 7:15:43 AM5/13/05
to
<ka...@gabi-soft.fr> wrote in message
news:1115810681.9...@g14g2000cwa.googlegroups.com...

>
> > Compaq/HP C++ V6.5 on OpenVMS (an EDG-based compiler).
> > boost/bind.h, a slightly modified scopeguard.h (from A.
> > Alexandrescu / P. Marginean), and my local library which
> > defines "finally".
>
> Which of course means that I can't compile it:-). (Of course,
> you didn't claim otherwise.)

I posted the code in another thread "finally for C++".

>
> The semantics of catch(...) are specified by the standard. You
> should be able to count on them.

Imagine an OS kernel implemented in C++, which (synchronously,
from the kernel's point-of-view) throws C++ exceptions in case of
errors asynchronously detected in user code (eg, access
violations, etc.). The type names of these exception objects are
not exposed to user code. Because they may be triggered
asynchronously from the point of view of the user code (and
therefore any sort of logic invariant conditions may be violated
at the time they are triggered), they are not really intended to
be handled or trigger stack-unwinding in the user code. They are
really intended only to be caught by the special C++ run-time
internal exception handler code at the top of the user stack (and
dump a core file, or something similar), *OR* (maybe) by special
platform-specific custom user exception-handler code (write to
your log file). Because they are C++ exceptions though,
catch(...) in user code would intercept them (and all sort of
sadness will ensue, because how do you know if you've just
intercepted an access-violation or a file-not-found error?). This
would be fully compliant behavior, of course. This is basically
the same 'observable semantics' anyhow of an OS which throws
non-C++ exceptions that still fall into catch(...) blocks.

>I've never had any
> problem with it, but then, I've never used a compiler which
> mixed up system traps (which generate signals everywhere I've
> worked) and exceptions.

This issue is especially relevant for VMS and Windows. There's a
workaround for Windows that is supposed to prevent OS exceptions
from triggering catch(...) blocks, but I'm not convinced that it
actually works consistently well (as we have something similar on
VMS, and it doesn't work consistently well). Better not to use
catch(...) at all, I think.

>
> Of course, in this particular case, I actually have a class
> which removes a file in its destructor (two, in fact -- one
> which supports commit, and one which doesn't). So of course, I
> would use of of them, rather than catch(...) or finally, or any
> new mechanism which came along.
>

This RAII-based form of finally() (and any of the scopeguard
family), using boost::bind() to provide construction of arbitrary
function object invocations, can really give convenient and
flexible destructor-based cleanup semantics, and it's much safer
than a C#/Java-like "try/finally" scheme would be in the context
of C++.

--
Hillel Y. Sims
hsims AT factset.com
FactSet Research Systems

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

The Sim

unread,
May 13, 2005, 7:13:51 AM5/13/05
to

"Andrei Alexandrescu (See Website For Email)"
<SeeWebsit...@moderncppdesign.com> wrote in message
news:IGAK1...@beaver.cs.washington.edu...

I'll post the code here, because it's actually quite short:

finally.h
---------
#include "scopeguard.h"

#define GuardRegion(guardname, op) if (ScopeGuard guardname =
MakeScopeGuard(op)) { throw; } else
#define finally(op)
GuardRegion(SCOPEGUARD_ANONYMOUS_VARIABLE(finallyGuard), op)
---------

(Note: we simply renamed ScopeGuard's ANONYMOUS_VARIABLE macro
with the SCOPEGUARD_ tag)

and requires one change to your local copy of scopeguard.h, add
the following function:
-------
class ScopeGuardImplBase {
public:
// operator 'safe-bool'


operator const void*() const { return 0; }
};

-------

(If anyone wants to do a "really" safe-bool there, please feel
free..)

That's it, now you have a working RAII-based finally(), 100%
standard portable C++. GuardRegion() is simply a named cleanup
region, that can be Dismiss()ed. I recommend the use of
boost::bind() to pass arbitrary function objects with any number
of parameters; boost::ref()/cref() to capture references to local
objects.

"almost real-life" example:
void ThreadedObj::SetParams(const Params& newparams)
{
// notify worker thread when done here
finally(bind(&CondVar::signal, ref(m_cv))) {
LockRegion(m_mx) {
finally(bind(&ThreadedObj::ChangeState, this,
REFRESH_PARAMS)) {
// we always want to generate a refresh; but if an
// exception occurs while updating our state, we will
// clear everything out
GuardRegion(paramguard, bind(&Params::clear,
ref(m_threadparams))) {
// now some code that can throw.
m_threadparams = newparams;
paramguard.Dismiss(); // "commit"
}
}
} // LockRegion
}
}

<Paris Hilton> "THAT'S HOT!"

(There are a few other suggestions I have for improvements to
ScopeGuard, but we can discuss in another thread.)

--
Hillel Y. Sims
hsims AT factset.com
FactSet Research Systems

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Andrei Alexandrescu (See Website for Email)

unread,
May 14, 2005, 8:03:49 AM5/14/05
to
Roland Pibinger wrote:
> On 11 May 2005 07:09:39 -0400, "Andrei Alexandrescu (See Website For
> Email)" <SeeWebsit...@moderncppdesign.com> wrote:
>
>
>>The example I give in my talk on ScopeGuard is a simple function that
>>adds a record to a database, and to the in-memory cache of the database.
>>The function has two failure points as both actions might fail. While
>>considering an entry in a vector a resource and writing a class
>>PopBacker to dispose of it works, it is a stretch. You care about
>>removing an entry from the vector if the database action fails, and an
>>implementation based on ScopeGuard is shorter and arguably easier to
>>understand than other approaches.
>
>
> Hmm,
>
> void SomeClass::foo() throw (DBException) {
> // ...
> recordCache.tryInsert (pRecord);
> insertIntoDB (pRecord);
> recordCache.commitInsert (pRecord);
> }
>
> No ScopeGuard and no try/catch.

But you moved all of the complexity in the unpublished recordCache
class! This is cheating! :o) In formal logic terms, there is no
"progress" being made (no reduction in the formula size). My example
uses a plain vanilla std::vector.

Andrei

James Kanze

unread,
May 16, 2005, 12:25:23 PM5/16/05
to
The Sim wrote:
> <ka...@gabi-soft.fr> wrote in message
> news:1115810681.9...@g14g2000cwa.googlegroups.com...

>>>Compaq/HP C++ V6.5 on OpenVMS (an EDG-based compiler).
>>>boost/bind.h, a slightly modified scopeguard.h (from A.
>>>Alexandrescu / P. Marginean), and my local library which
>>>defines "finally".

>>Which of course means that I can't compile it:-). (Of course,
>>you didn't claim otherwise.)

> I posted the code in another thread "finally for C++".

I think I saw it in passing. I'll have to look into it (while
waiting for a true language based solution).

>>The semantics of catch(...) are specified by the standard.
>>You should be able to count on them.

> Imagine an OS kernel implemented in C++, which (synchronously,
> from the kernel's point-of-view) throws C++ exceptions in case
> of errors asynchronously detected in user code (eg, access
> violations, etc.).

One of two things must be true: either your code has undefined
behavior, or the implementation is unconforming -- the standard
doesn't allow asynchronous exceptions, so in the absence of
undefined behavior, an implementation can't raise them. If the
first is true, that your application has undefined behavior, the
obvious answer is: don't do it. If the second is true, the
obvious answer is: don't use that system.

But I know: the "obvious" answers aren't necessarily easy:-).

> The type names of these exception objects are not exposed to
> user code. Because they may be triggered asynchronously from
> the point of view of the user code (and therefore any sort of
> logic invariant conditions may be violated at the time they
> are triggered), they are not really intended to be handled or
> trigger stack-unwinding in the user code. They are really
> intended only to be caught by the special C++ run-time
> internal exception handler code at the top of the user stack
> (and dump a core file, or something similar), *OR* (maybe) by
> special platform-specific custom user exception-handler code
> (write to your log file). Because they are C++ exceptions
> though, catch(...) in user code would intercept them (and all
> sort of sadness will ensue, because how do you know if you've
> just intercepted an access-violation or a file-not-found
> error?). This would be fully compliant behavior, of course.
> This is basically the same 'observable semantics' anyhow of an
> OS which throws non-C++ exceptions that still fall into
> catch(...) blocks.

It's fully compilant if, and only if, your program has undefined
behavior (in which case, whatever the system does is fully
compliant). One can argue about the usefulness, or the quality
of such an implementation, but of course, the official answer
is: don't have undefined behavior.

I say official because in practice, there are certain cases
(like stack overflow) where undefined behavior is pratically
unavoidable.

>>I've never had any problem with it, but then, I've never used
>>a compiler which mixed up system traps (which generate signals
>>everywhere I've worked) and exceptions.

> This issue is especially relevant for VMS and Windows.
> There's a workaround for Windows that is supposed to prevent
> OS exceptions from triggering catch(...) blocks, but I'm not
> convinced that it actually works consistently well (as we have
> something similar on VMS, and it doesn't work consistently
> well). Better not to use catch(...) at all, I think.

Or limit yourself to compilers which don't do stupid things. Or
not have the undefined behavior there in the first place -- if I
understand the situation correctly under Windows, the problem
only occurs as a reaction to undefined behavior in the user
program. In which case, I suppose that it's always better than
reformatting the hard disk -- it's very hard to make a program
generally robust against programming errors.

>>Of course, in this particular case, I actually have a class
>>which removes a file in its destructor (two, in fact -- one
>>which supports commit, and one which doesn't). So of course,
>>I would use of of them, rather than catch(...) or finally, or
>>any new mechanism which came along.

> This RAII-based form of finally() (and any of the scopeguard
> family), using boost::bind() to provide construction of
> arbitrary function object invocations, can really give
> convenient and flexible destructor-based cleanup semantics,
> and it's much safer than a C#/Java-like "try/finally" scheme
> would be in the context of C++.

It sounds useful. Even more useful, of course, would be
arbitrary code (not just a function) with full access to local
variables, but every little bit helps.

--
James Kanze mailto: james...@free.fr


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

0 new messages