Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > RAII and cleanup functions that can throw

Reply
Thread Tools

RAII and cleanup functions that can throw

 
 
Kenneth Porter
Guest
Posts: n/a
 
      01-10-2007
I've read this article and have some followup questions.

http://groups.google.com/group/comp....wse_thread/thr
ead/9d5324ce02f4d89b/

I'm working on an embedded robotics application that cannot terminate.

I often have the need to temporarily change some setting before
performing an operation. If the operation fails, I still need to restore
the original setting. It's possible for the restore operation to fail
(eg. a communication fault that temporarily prevents the request from
reaching the hardware), in which case user intervention is required. The
application can later re-initialize the system to a known state.

A typical scenario, written in C (assuming a zero errorcode means no
error):

int oldvalue;
int errorcode = SaveOldValue(&oldvalue);
if (!errorcode)
errorcode = SetValue(newvalue);
if (!errorcode)
errcode = PerformOperation();
int errcode2 = SetValue(oldvalue);
return errcode ? errcode : errcode2;

This idiom might be nested.

With C++, it seems like I should report errors via exceptions, and
perform the temporary settings changes with RAII objects (to insure that
original settings are restored through all error paths).

How can I capture the error if the restore operation fails? Do I simply
use uncaught_exception() in the RAII dtor to throw only if I'm not
handling an exception from the main operation?
 
Reply With Quote
 
 
 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      01-10-2007
* Kenneth Porter:
> I've read this article and have some followup questions.
>
> http://groups.google.com/group/comp....wse_thread/thr
> ead/9d5324ce02f4d89b/
>
> I'm working on an embedded robotics application that cannot terminate.
>
> I often have the need to temporarily change some setting before
> performing an operation. If the operation fails, I still need to restore
> the original setting. It's possible for the restore operation to fail
> (eg. a communication fault that temporarily prevents the request from
> reaching the hardware), in which case user intervention is required. The
> application can later re-initialize the system to a known state.
>
> A typical scenario, written in C (assuming a zero errorcode means no
> error):
>
> int oldvalue;
> int errorcode = SaveOldValue(&oldvalue);
> if (!errorcode)
> errorcode = SetValue(newvalue);
> if (!errorcode)
> errcode = PerformOperation();
> int errcode2 = SetValue(oldvalue);
> return errcode ? errcode : errcode2;
>
> This idiom might be nested.
>
> With C++, it seems like I should report errors via exceptions, and
> perform the temporary settings changes with RAII objects (to insure that
> original settings are restored through all error paths).
>
> How can I capture the error if the restore operation fails? Do I simply
> use uncaught_exception() in the RAII dtor to throw only if I'm not
> handling an exception from the main operation?


Note that the C-style code above "solves" the double exception/error
problem by, in the last line, discarding errcode2 (the SetValue error)
if any operation before that fails.

To do /the same/ using C++ exceptions instead of error codes:

struct ValueUsageWrapper
{
int myOriginal;
bool myShouldReportRestoreError;

static int current()
{
int v;
if( SaveOldValue( &v ) != 0 ) { throw ValueAccessException(); }
return v;
}

static void set( int v )
{
if( SetValue( v ) != 0 ) { throw ValueAccessException(); }
}

ValueUsageWrapper()
: myOriginal( current() )
, myShouldReportRestoreError( false )
{}

~ValueUsageWrapper()
{
try
{
set( myOriginal );
}
catch( ... )
{
if( myShouldReportRestoreError ) { throw; }
}
}

void reportAnyRestoreError() { myShouldReportRestoreError = true; }
};

void performOperationOrX()
{
if( PerformOperation() != 0 ) { throw SomeThing(); }
}

void foo( int newValue )
{
ValueUsageWrapper valueUsage;

valueUsage.set( newValue );
performOperationOrX();
valueUsage.reportAnyRestoreError();
}

But again, note that by design -- yours!, the C-style code --
the client code will not be aware of failure to restore the value if any
operation before that fails. This is discussed in the FAQ. As an
exercise, find the relevant FAQ item.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
 
 
 
=?ISO-8859-15?Q?Juli=E1n?= Albo
Guest
Posts: n/a
 
      01-10-2007
Kenneth Porter wrote:

> I often have the need to temporarily change some setting before
> performing an operation. If the operation fails, I still need to restore
> the original setting. It's possible for the restore operation to fail
> (eg. a communication fault that temporarily prevents the request from
> reaching the hardware), in which case user intervention is required. The
> application can later re-initialize the system to a known state.

(snip)
> How can I capture the error if the restore operation fails? Do I simply
> use uncaught_exception() in the RAII dtor to throw only if I'm not
> handling an exception from the main operation?


IMO will be better that the system works as finite state automata, and set
the system state to "Intervention required". By means of a global function,
of by having in the RAII object a reference to the object that maintains
the state, or any other way appropriate for your application. The general
rule is to avoid to throw from destructors.

--
Salu2
 
Reply With Quote
 
Roland Pibinger
Guest
Posts: n/a
 
      01-11-2007
On Wed, 10 Jan 2007 16:24:06 -0600, Kenneth Porter wrote:
>With C++, it seems like I should report errors via exceptions, and


Not necessarily. In your case an error value may be more appropriate.

>perform the temporary settings changes with RAII objects (to insure that
>original settings are restored through all error paths).


Good idea.

>How can I capture the error if the restore operation fails?


You cannot. An exception shall never be thrown from a destructor and a
return value is impossible. Therefore the general rule is to use only
code in the destructor that either cannot throw or that only throws an
exception that can safely be ignored. In the latter case the (ignored)
exception must be cought in the destructor (preferably with catch
(...)). Other code must be put in member functions but not in the
destuctor.

>Do I simply
>use uncaught_exception() in the RAII dtor to throw only if I'm not
>handling an exception from the main operation?


See e.g. http://www.gotw.ca/gotw/047.htm

Best wishes,
Roland Pibinger
 
Reply With Quote
 
Kenneth Porter
Guest
Posts: n/a
 
      01-16-2007
=?ISO-8859-15?Q?Juli=E1n?= Albo <(E-Mail Removed)> wrote in
news:(E-Mail Removed):

> IMO will be better that the system works as finite state automata, and
> set the system state to "Intervention required". By means of a global
> function, of by having in the RAII object a reference to the object
> that maintains the state, or any other way appropriate for your
> application. The general rule is to avoid to throw from destructors.


Ah, so instead of throwing the exception, the destructor could invoke an
append method on a global fault object that's monitored as part of the
background loop, and before any critical operation takes place (ie. in my
application, anything that operates a physical actuator).
 
Reply With Quote
 
Grizlyk
Guest
Posts: n/a
 
      01-16-2007

Kenneth wrote:

> How can I capture the error if the restore operation fails? Do I simply
> use uncaught_exception() in the RAII dtor to throw only if I'm not
> handling an exception from the main operation?


I make global stack (vector) to hold errors. When your object of class
of error is created, the object makes "record" in the stack, so you can
skip double throw.

if (your_error_condition)
{
//here disable optimisation to prevent moving "tmp" to
if(!uncaught_exception()) block
//i am not shure, that it is needed
auto volatile

//here error added to you stack;
Class_of error tmp;

//here you can do not rhrow, remain old error - new error will be on
your stack also
if(!uncaught_exception())throw tmp;
}

It is not "checked by time" solution, new for me.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
problem in running a basic code in python 3.3.0 that includes HTML file Satabdi Mukherjee Python 1 04-04-2013 07:48 PM
Re: Why is RAII called RAII? Johannes Schaub (litb) C++ 2 09-18-2010 09:18 AM
Re: Why is RAII called RAII? Goran Pusic C++ 11 09-16-2010 03:11 PM
Re: Why is RAII called RAII? cpp4ever C++ 1 09-13-2010 06:25 AM
Throw Exception Vs Throw New Exception Kerri ASP .Net 2 10-27-2003 02:13 PM



Advertisments