Can I tell in the destructor if an exception occured ?

T

Timothy Madden

Hy

I have destructors that do some functional work in the program flow.
The problem is destructors should only be used for clean-up, because
exceptions might rise at any time, and destructors will be called for
clean-up only.

So how can I tell, from within the destructor, if the call has been made as
part of normal flow of control and the destructor can play its functional
role, or if the call has been made as a result of an exception and the
destructor should rollback, abort and clean up ?

What if I need to propagate this state to other destructors that are called
before the current destructor returns, so that the other destructors can
take appropiate action ?

How come there is no real way to comunicate with the destructors ?
Constructors I can choose, I can pass parameters to, but for destructors ?

Thank you
"Timothy Madden"
Romania
 
B

Bob Hairgrove

Hy

I have destructors that do some functional work in the program flow.
The problem is destructors should only be used for clean-up, because
exceptions might rise at any time, and destructors will be called for
clean-up only.

So how can I tell, from within the destructor, if the call has been made as
part of normal flow of control and the destructor can play its functional
role, or if the call has been made as a result of an exception and the
destructor should rollback, abort and clean up ?

What if I need to propagate this state to other destructors that are called
before the current destructor returns, so that the other destructors can
take appropiate action ?

How come there is no real way to comunicate with the destructors ?
Constructors I can choose, I can pass parameters to, but for destructors ?

Thank you
"Timothy Madden"
Romania

uncaught_exception() will tell you. But many compilers apparently have
had trouble with it until only recently, e.g. GCC 3.4 was reported to
handle it OK, whereas earlier versions did not.
 
T

Timothy Madden

Bob Hairgrove said:
uncaught_exception() will tell you. But many compilers apparently have
had trouble with it until only recently, e.g. GCC 3.4 was reported to
handle it OK, whereas earlier versions did not.
I tryed it on my platform (80x86, Win2000, VC++ 6.0 SP5), it doesn't work
:(
Anything else I can do ?
Anything ?

Thank you
"Timothy Madden"
Romania
 
B

Bob Hairgrove

I tryed it on my platform (80x86, Win2000, VC++ 6.0 SP5), it doesn't work
:(
Anything else I can do ?

Yes. Update your compiler to MSVC++ 7.1 ... quickly. Version 6 is
broken in many ways. BTW you can download the command-line version for
free from the MS website, called "MS Visual C++ Toolkit". The drawback
is that they only provide static libraries to link with the C/C++
runtime libraries. But otherwise, it is fully functional and you can
use code optimizations.

Unfortunately, I have never had occasion to use uncaught_exception
myself yet, so I cannot say whether it works with this compiler or
not.
 
S

slurper

Timothy said:
Hy

I have destructors that do some functional work in the program flow.
The problem is destructors should only be used for clean-up, because
exceptions might rise at any time, and destructors will be called for
clean-up only.

seems to me like a strange design
why not do the functional work out of the destructor?
as you say, destructors should be called for cleanup (e.g. cleaning up a
socket, call other object's destructor, ...) , not for common logic in your
program. you can put the logic before you're object is going out of scope
(and the destructor will be called) (or before a manual call to the
destructor)
So how can I tell, from within the destructor, if the call has been made
as part of normal flow of control and the destructor can play its
functional role, or if the call has been made as a result of an exception
and the destructor should rollback, abort and clean up ?

What if I need to propagate this state to other destructors that are
called before the current destructor returns, so that the other
destructors can take appropiate action ?

a destructor should clean-up resources that this object hold. that's the
only purpose. if this object is destroyed, ask yourself which other objects
need to be destroyed.
if an error occurs, you can catch the exception and do whatever needs to be
done in the exception handler (possibly destroying resources). if no error
occurs, just do what you mean to do according to normal flow of execution.
remember that the destructor should never contain "normal program
flow"-code.
 
T

Timothy Madden

slurper said:
seems to me like a strange design
why not do the functional work out of the destructor?
as you say, destructors should be called for cleanup (e.g. cleaning up a
socket, call other object's destructor, ...) , not for common logic in your
program. you can put the logic before you're object is going out of scope
(and the destructor will be called) (or before a manual call to the
destructor)
Yes it is, I have no better ideea. However if anyone knows please tell me
what could be the solution.

I wrote a class used to fill in records in tables from a relational
database.
Records in a related table should be updated and commited in the database
only after the coresponding record in the master table, to respect
referential integrity. The purpose of the class is to allow the application
to fill the tables in whatever order it wishes, provided that when everey
record is done, overall referential integrity is respected.

The strategy is to buffer update requests on the related table until the
master table is updated, when the related updates are also flushed/commited.

The objects of the class just fill in filelds in the record. The update
happens automaticaly in the destructor, if if is possible, followed by
updates of related records. If it is not possible (the master table is not
ready yet) then the destructor buffers the update command and lets the
destructor of the master table do the job when it gets called.

Someone has a better way to do this without destructors ?

Thank you
"Timothy Madden"
Romania
 
S

slurper

Timothy said:
Yes it is, I have no better ideea. However if anyone knows please tell me
what could be the solution.

I wrote a class used to fill in records in tables from a relational
database.
Records in a related table should be updated and commited in the database
only after the coresponding record in the master table, to respect
referential integrity. The purpose of the class is to allow the
application to fill the tables in whatever order it wishes, provided that
when everey record is done, overall referential integrity is respected.

The strategy is to buffer update requests on the related table until the
master table is updated, when the related updates are also
flushed/commited.

The objects of the class just fill in filelds in the record. The update
happens automaticaly in the destructor, if if is possible, followed by
updates of related records. If it is not possible (the master table is not
ready yet) then the destructor buffers the update command and lets the
destructor of the master table do the job when it gets called.

Someone has a better way to do this without destructors ?

if i understand well: why not first write the logic to update the master
table and then write the logic to update the table which references the
master table? (in a sequential manner) you can combine both operations on
the database in a transaction if your database management system supports
it (but that's not necessary per se). why do you want to put that in a
destructor?
 
B

Bob Hairgrove

I wrote a class used to fill in records in tables from a relational
database.
Records in a related table should be updated and commited in the database
only after the coresponding record in the master table, to respect
referential integrity. The purpose of the class is to allow the application
to fill the tables in whatever order it wishes, provided that when everey
record is done, overall referential integrity is respected.

The strategy is to buffer update requests on the related table until the
master table is updated, when the related updates are also flushed/commited.

The objects of the class just fill in filelds in the record. The update
happens automaticaly in the destructor, if if is possible, followed by
updates of related records. If it is not possible (the master table is not
ready yet) then the destructor buffers the update command and lets the
destructor of the master table do the job when it gets called.

Someone has a better way to do this without destructors ?

Perhaps. It would depend on the RDBMS you have.

In general, such multi-table updates are best wrapped in a transaction
which can be committed or rolled back as a whole. If you indeed have a
referential DBMS, then you should have foreign key constraints in
place, otherwise it is very dangerous to do what you are trying to do
(i.e. enforce referential integrity in the application instead of in
the database) because of the danger of inconsistent data when
something goes wrong.
 
P

puppet_sock

Timothy Madden said:
I have destructors that do some functional work in the program flow.
The problem is destructors should only be used for clean-up, because
exceptions might rise at any time, and destructors will be called for
clean-up only.

Um. Not sure I'm following what you mean. Can you give some more
description of what you mean by "functional work in the program
flow?" Because destructors *should* only get called for cleanup.
(And resource deallocation, and such like.) So, I'm thinking
you've done something pretty strange.
Socks
 
T

Timothy Madden

Bob Hairgrove said:
Perhaps. It would depend on the RDBMS you have.

In general, such multi-table updates are best wrapped in a transaction
which can be committed or rolled back as a whole. If you indeed have a
referential DBMS, then you should have foreign key constraints in
place, otherwise it is very dangerous to do what you are trying to do
(i.e. enforce referential integrity in the application instead of in
the database) because of the danger of inconsistent data when
something goes wrong.
I can't say what RDBMS I have because I do not relay on one of them.
I can change the DBMS as this choice does not affect the application and I
currently am not satisfied with the one I use (Access 2000).
Transaction support is a property of the DBMS so there isn't much I can do
about it in the application. I have set foreign key constraints in the
database
and I try to follow them in the app (not enforce them); this is way I've
done
my class.

Thank you
"Timothy Madden"
Romania
 
T

Timothy Madden

slurper said:
Timothy said:
[ ... ]
I wrote a class used to fill in records in tables from a relational
database.
Records in a related table should be updated and commited in the database
only after the coresponding record in the master table, to respect
referential integrity. The purpose of the class is to allow the
application to fill the tables in whatever order it wishes, provided that
when everey record is done, overall referential integrity is respected.

The strategy is to buffer update requests on the related table until the
master table is updated, when the related updates are also
flushed/commited.

The objects of the class just fill in filelds in the record. The update
happens automaticaly in the destructor, if if is possible, followed by
updates of related records. If it is not possible (the master table is not
ready yet) then the destructor buffers the update command and lets the
destructor of the master table do the job when it gets called.

Someone has a better way to do this without destructors ?

if i understand well: why not first write the logic to update the master
table and then write the logic to update the table which references the
master table? (in a sequential manner) you can combine both operations on
the database in a transaction if your database management system supports
it (but that's not necessary per se). why do you want to put that in a
destructor?
There is no difference between master tables and related tables. Any table
can be master and related in the same time. There is only one class. The
tables relationship view in the database shows something like a big tree. I
use destructors so that I can provide data to be entered in the tables in
any order the app needs, and on the destructor the decision is made about
whether the table can be immediatly updated or should wait for the update on
some master table.

Thank you
"Timothy Madden"
Romania
 
T

Timothy Madden

"Timothy Madden" <[email protected]> wrote in message

Um. Not sure I'm following what you mean. Can you give some more
description of what you mean by "functional work in the program
flow?" Because destructors *should* only get called for cleanup.
(And resource deallocation, and such like.) So, I'm thinking
you've done something pretty strange.
Socks

Yes, but you may find cases when the destructors have other functions in the
normal
flow of control. For example a class for a windows on screen in a GUI should
of course close the window in the destructor if it has not been already
closed. Or a class for a buffered stream should of course flush the buffer
and close the stream. Flushing a buffer on disk may cause an exception,
after the first attempt to write in the buffer has already generated
exceptions.

Think of a class that wrapps some generic process, that in normal usage just
collects a lot of input for the process. Only after the desctructor gets
called can you be sure no more input is going to be delinvered for the
process and in the destructor you can now start and perform the process to
its finish.

Thank you
"Timothy Madden"
Romania
 
S

Stephan Br?nnimann

[snip]
Yes, but you may find cases when the destructors have other functions in the
normal
flow of control. For example a class for a windows on screen in a GUI should
of course close the window in the destructor if it has not been already
closed. Or a class for a buffered stream should of course flush the buffer
and close the stream. Flushing a buffer on disk may cause an exception,
after the first attempt to write in the buffer has already generated
exceptions.

Think of a class that wrapps some generic process, that in normal usage just
collects a lot of input for the process. Only after the desctructor gets
called can you be sure no more input is going to be delinvered for the
process and in the destructor you can now start and perform the process to
its finish.

Thank you
"Timothy Madden"
Romania

struct Main {
// allocate pImpl_;
Main();
// does all the program work
~Main();
private:
struct Impl;
Impl* pImpl_;
};

int main()
{
Main m;
return 0;
}

If this looks strange to you: I agree. It's just taking your logic to
an extreme.

Let's get more serious now:

Don't be afraid of specifying requirements to the user of your DB interface.
+ If you write data to me (the DB interface) then you have to call
flush().
+ If you forget to do this, I will do it in my destructor. However please
be aware that any errors will be remain unhandled and you have no
way to find out if the data was actually written to the DB.


Stephan Brönnimann
(e-mail address removed)
Open source rating and billing engine for communication networks.
 
P

puppet_sock

Timothy Madden said:
Yes, but you may find cases when the destructors have other functions in the
normal
flow of control. For example a class for a windows on screen in a GUI should
of course close the window in the destructor if it has not been already
closed. Or a class for a buffered stream should of course flush the buffer
and close the stream. Flushing a buffer on disk may cause an exception,
after the first attempt to write in the buffer has already generated
exceptions.

In that case, the flush operation should catch the exception and handle
it appropriately. If the dtor *can't* deal with the exception, then you
should reconsider the design of your system so that either the exception
can't be thrown in the dtor or the dtor *can* deal with the exception.

For example, if the data stream belongs to the object, then the object
should do whatever is appropriate about errors on the stream. If the
data stream does *not* belong to the object, it should not be doing
the closing ops on the stream.

If a resource requires some extraordinary care at shutdown, then
you may want to rethink the notion of using the standard dtor
mechanism. For example, if you were dealing with some sensitive
hardware that required some special actions to be guaranteed to
take place on shutdown, you may want to do something very special
about its control from code. But such situations would be quite rare.
Think of a class that wrapps some generic process, that in normal usage just
collects a lot of input for the process. Only after the desctructor gets
called can you be sure no more input is going to be delinvered for the
process and in the destructor you can now start and perform the process to
its finish.

Um. I'm pretty sure I'd never do things that way. If the data is going
to be unsolicited, user input for example, you need to have some way
of polling. And when you are done polling, you shut things down and
*don't* accept any more input. If, in the dtor, some "orphaned"
input has been received, then you dispose of it appropriately.
Socks
 
P

pembed2003

Timothy Madden said:
So how can I tell, from within the destructor, if the call has been made as
part of normal flow of control and the destructor can play its functional
role, or if the call has been made as a result of an exception and the
destructor should rollback, abort and clean up ?

Don't know exactly what you mean but can you do something like:

class Foo{
public:
Foo() : caughtException(false){}
void hasException(bool b){caughtException = b;}
~Foo(){
if(caughtException)
// has exception
else
// normal exit
}
private:
bool caughtException;
};

later:

Foo f;
try{
throw 1;
}catch(int){
f.hasException(true);
}

not sure if that's what you want.
 
C

Chris F Clark

Timothy Madden said:
I have destructors that do some functional work in the program flow.
The problem is destructors should only be used for clean-up, because
exceptions might rise at any time, and destructors will be called for
clean-up only.

Contrary to most other respondents, I don't think your design is so
bizarre. However, there is a "better" solution. Instead of coding
the "normal functional" work in the destructor, put the normal
funcitonal work in a "finalizeAndDelete()" member function.

The finalizeAndDelete() member function can do the writing of the
objects to the DBMS and check the ordering constraints, calling the
appropriate finalizeAndDelete() members of the other tables as needed,
after it has done all the work then, it cleans up the object setting
it into a state ssaying that it has been successfully written, and as
the very last thing deletes the object itself. Strictly speaking, you
don't need to delete the object in the function, but you probably wish
to to prevent the object from getting "re-used" by later changes in
the logic.

The destructor then can check to see if the object has been
succesfully written (i.e. finalizeAndDelete() was called on it) or not
and do the appropriate clean up to handle aborts etc.

It amy seem simpler to put the code which belongs in the member
function finalizeAndDelete() in the destructor, since C++ assures one
that the destructor will be called. However, in your case where you
have exception issues, keeping that code out of the destructor will
lead to a simpler solution overall. Yes, you have to assure that
finalizeAndDelete is called. HOwever, that is actually not such an
onerous requirement.

Hope this helps,
-Chris

*****************************************************************************
Chris Clark Internet : (e-mail address removed)
Compiler Resources, Inc. Web Site : http://world.std.com/~compres
23 Bailey Rd voice : (508) 435-5016
Berlin, MA 01503 USA fax : (978) 838-0263 (24 hours)
------------------------------------------------------------------------------
 
C

Chris F Clark

I wrote the following rubish:
It may seem simpler to put the code which belongs in the member
function finalizeAndDelete() in the destructor, since C++ assures one
that the destructor will be called.

Of course, C++ doesn't guarantee that destructors are called for
objects on the "heap" and other circumstances. Only stack based
objects have nice destructor properties and even there, if one does
things which make copies, the rules can get more complex that I want
to deal with.

However, normal C++ coding practices often involve approaches to make
certain that desructors are called at the appropriate times (by having
classes destroy the objects "owned" by them and related techniques).
The same techniques can be applied to "finalizeAndDelete()" member
function calls and that was my point.

My apologies for the error I made above. I hope no one gets misled by
it.

Hope this helps,
-Chris

*****************************************************************************
Chris Clark Internet : (e-mail address removed)
Compiler Resources, Inc. Web Site : http://world.std.com/~compres
23 Bailey Rd voice : (508) 435-5016
Berlin, MA 01503 USA fax : (978) 838-0263 (24 hours)
------------------------------------------------------------------------------
 

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

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top