try...finally semantics

R

Rolf Magnus

Daniel said:
Hi all,

I just needed some kind of try...finally semantics in a method and was
wondering how to do this "the best way" -- there were two alternatives
which came to my mind:

1) RAII:

void A::method()
{
// Stuff here

// This is the "try...finally"
{
class Finally
{
private:
A& me;
public:
inline Finally(A& m)
: me(m)
{}
inline ~Finally()
{
me.foo=bar;
me.doSomething();
}
} finally(*this);
// Do the throwing stuff
}

// Stuff here
}

2) Catch and rethrow:

void A::method()
{
// Stuff here

#define DO_FINALLY \
foo=bar; \
doSomething();
try
{
// throwing stuff
} catch(...)
{
DO_FINALLY
throw;
}
DO_FINALLY
#undef DO_FINALLY

// Stuff here
}

Of course the RAII thing is "really" like try...finally, as for instance
an early return is caught, too, but the same is not true for 2); and 1)
seems much "cleaner" to me. However, there is some amount of bloat in
1) which seems to make the code a bit unreadable for me.

I believe most C++ programmers must have had a need for try...finally
functionality at some point, and I'd like to know how you solved it /
how you would recommend to solve it. Is there maybe some way I did not
think about?

Usually, if your classes are properly designed with a destructor that cleans
up, you get RAII implicitly and there is no need for 'finally'. Dynamically
allocated objects can be handled with std::auto_ptr if you don't already
use some type of shared pointer.
 
D

Daniel Kraft

Hi all,

I just needed some kind of try...finally semantics in a method and was
wondering how to do this "the best way" -- there were two alternatives
which came to my mind:

1) RAII:

void A::method()
{
// Stuff here

// This is the "try...finally"
{
class Finally
{
private:
A& me;
public:
inline Finally(A& m)
: me(m)
{}
inline ~Finally()
{
me.foo=bar;
me.doSomething();
}
} finally(*this);
// Do the throwing stuff
}

// Stuff here
}

2) Catch and rethrow:

void A::method()
{
// Stuff here

#define DO_FINALLY \
foo=bar; \
doSomething();
try
{
// throwing stuff
} catch(...)
{
DO_FINALLY
throw;
}
DO_FINALLY
#undef DO_FINALLY

// Stuff here
}

Of course the RAII thing is "really" like try...finally, as for instance
an early return is caught, too, but the same is not true for 2); and 1)
seems much "cleaner" to me. However, there is some amount of bloat in
1) which seems to make the code a bit unreadable for me.

I believe most C++ programmers must have had a need for try...finally
functionality at some point, and I'd like to know how you solved it /
how you would recommend to solve it. Is there maybe some way I did not
think about?

Thanks,
Daniel
 
R

Roland Pibinger

every once in
a while I need some kind of clean-up inside a method other than just
deleting resources and without the whole object being destroyed; for
instance:

void A::foo()
{
obj.setSomeFlag(true);
// Do something
obj.setSomeFlag(false);
}

Now I want to set the flag back to false on every occasion, even if an
exception is thrown in between.

What about:

void A::foo()
{
SetSomeFlag objFlag(obj, true);
// Do something

} // RAII resets flag here

If you still want a 'finally' in C++ look for 'scopeguard'.
 
G

Gianni Mariani

Daniel said:
Yes, of course, this is useful for most of the needs; but every once in
a while I need some kind of clean-up inside a method other than just
deleting resources and without the whole object being destroyed; for
instance:

void A::foo()
{
obj.setSomeFlag(true);
// Do something
obj.setSomeFlag(false);
}


template <typename T>
class FlagSetter
{
T & m_obj;
// don't allow copy or assignment
AFlagSetter & operator=( const AFlagSetter & );
AFlagSetter( const AFlagSetter & );

public:

AFlagSetter( T & i_obj )
: m_obj( i_obj )
{
m_obj.setSomeFlag(true);
}

~AFlagSetter()
{
m_obj.setSomeFlag(false);
}
};


void A::foo()
{
FlagSetter<objType> l_setter( obj );
// Do something


// - automagically happens ... obj.setSomeFlag(false);
}
Now I want to set the flag back to false on every occasion, even if an
exception is thrown in between.

You can create a more generic system than I showed above that would
allow you to provide different methods to start/end. If you want a
finally type functionality, this is the way to do it with C++.
 
G

Gianni Mariani

Daniel Kraft wrote:
.....
But it seems there is no better method, right?


Think like this: "creating a new class is a low threshold thing to do in
C++".

You may be able to make things by using some template magic. I would
need to know more specifically to see if there is some way of removing
"clutter". Having said that, there probably isn't too much clutter to
worry about when you look at it a bit closer.
 
D

Daniel Kraft

I believe most C++ programmers must have had a need for try...finally
Usually, if your classes are properly designed with a destructor that cleans
up, you get RAII implicitly and there is no need for 'finally'. Dynamically
allocated objects can be handled with std::auto_ptr if you don't already
use some type of shared pointer.

Yes, of course, this is useful for most of the needs; but every once in
a while I need some kind of clean-up inside a method other than just
deleting resources and without the whole object being destroyed; for
instance:

void A::foo()
{
obj.setSomeFlag(true);
// Do something
obj.setSomeFlag(false);
}

Now I want to set the flag back to false on every occasion, even if an
exception is thrown in between.

Yours,
Daniel
 
F

Frank Birbacher

Hi!

Daniel said:
void A::foo()
{
obj.setSomeFlag(true);
// Do something
obj.setSomeFlag(false);
}

Now I want to set the flag back to false on every occasion, even if an
exception is thrown in between.

Just an idea ;) :

using namespace boost::lambda;
using boost::shared_ptr;

const shared_ptr<bool> resetFlag(&obj.flag, *_1 = false);
....

or:

const shared_ptr<bool> resetFlag(&obj, bind(
&Obj::setSomeFlag,
_1,
false
));
....

Frank
 
D

Daniel Kraft

Yes, of course, this is useful for most of the needs; but every once
template <typename T>
class FlagSetter
{
T & m_obj;
// don't allow copy or assignment
AFlagSetter & operator=( const AFlagSetter & );
AFlagSetter( const AFlagSetter & );

public:

AFlagSetter( T & i_obj )
: m_obj( i_obj )
{
m_obj.setSomeFlag(true);
}

~AFlagSetter()
{
m_obj.setSomeFlag(false);
}
};


void A::foo()
{
FlagSetter<objType> l_setter( obj );
// Do something


// - automagically happens ... obj.setSomeFlag(false);
}

You can create a more generic system than I showed above that would
allow you to provide different methods to start/end. If you want a
finally type functionality, this is the way to do it with C++.

This is actually how I do it at the moment--using a class local to my
method similar to the one above; but as setting a flag was only an
example of one specific need for such a functionality, I always have to
implement such a class for every case (maybe once closures are available
this can be done with a generic class but up to now I did not find a
generic way for every situation; using a functor object just has the
same verbosity when defining this object).

Which of course works--my point was just I find those "clutter"
associated with defining the class, the constructor, initializing the
reference to my enclosing class and so on a bit confusing and negative
to readability to my code.

But it seems there is no better method, right?

Yours,
Daniel
 
D

Daniel Kraft

But it seems there is no better method, right?
Think like this: "creating a new class is a low threshold thing to do in
C++".

You may be able to make things by using some template magic. I would
need to know more specifically to see if there is some way of removing
"clutter". Having said that, there probably isn't too much clutter to
worry about when you look at it a bit closer.

Yeah, probably you are right ;)
Thank you!
Daniel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,818
Latest member
Brigette36

Latest Threads

Top