Can I tell in the destructor if an exception occured ?

Discussion in 'C++' started by Timothy Madden, Nov 17, 2004.

  1. 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
     
    Timothy Madden, Nov 17, 2004
    #1
    1. Advertising

  2. On Wed, 17 Nov 2004 12:47:27 +0200, "Timothy Madden"
    <> wrote:

    >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.

    --
    Bob Hairgrove
     
    Bob Hairgrove, Nov 17, 2004
    #2
    1. Advertising

  3. "Bob Hairgrove" <> wrote in message
    news:...
    > On Wed, 17 Nov 2004 12:47:27 +0200, "Timothy Madden"
    > <> wrote:
    >
    > >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.
    >

    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
     
    Timothy Madden, Nov 17, 2004
    #3
  4. On Wed, 17 Nov 2004 14:02:21 +0200, "Timothy Madden"
    <> wrote:

    >> 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
    :mad:
    > 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.

    --
    Bob Hairgrove
     
    Bob Hairgrove, Nov 17, 2004
    #4
  5. Timothy Madden

    slurper Guest

    Timothy Madden wrote:

    > 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.
    >
    > 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
     
    slurper, Nov 17, 2004
    #5
  6. "slurper" <> wrote in message
    news:419b5790$0$13457$...
    > Timothy Madden wrote:
    >
    > > 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)
    >

    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
     
    Timothy Madden, Nov 17, 2004
    #6
  7. Timothy Madden

    slurper Guest

    Timothy Madden wrote:

    >
    > "slurper" <> wrote in message
    > news:419b5790$0$13457$...
    >> Timothy Madden wrote:
    >>
    >> > 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)
    >>

    > 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?

    >
    > Thank you
    > "Timothy Madden"
    > Romania
     
    slurper, Nov 17, 2004
    #7
  8. On Wed, 17 Nov 2004 16:37:57 +0200, "Timothy Madden"
    <> wrote:

    >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.

    --
    Bob Hairgrove
     
    Bob Hairgrove, Nov 17, 2004
    #8
  9. Timothy Madden

    Guest

    "Timothy Madden" <> wrote in message news:<>...
    > 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
     
    , Nov 17, 2004
    #9
  10. "Bob Hairgrove" <> wrote in message
    news:...
    > On Wed, 17 Nov 2004 16:37:57 +0200, "Timothy Madden"
    > <> wrote:
    >
    > >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.
    >

    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
     
    Timothy Madden, Nov 18, 2004
    #10
  11. "slurper" <> wrote in message
    news:419bb3b7$0$13473$...
    > Timothy Madden wrote:
    >
    > >

    [ ... ]
    > > 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
     
    Timothy Madden, Nov 18, 2004
    #11
  12. <> wrote in message
    news:...
    > "Timothy Madden" <> wrote in message

    news:<>...
    > > 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


    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
     
    Timothy Madden, Nov 18, 2004
    #12
  13. "Timothy Madden" <> wrote in message news:<>...

    [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

    Open source rating and billing engine for communication networks.
     
    Stephan Br?nnimann, Nov 18, 2004
    #13
  14. Timothy Madden

    Guest

    "Timothy Madden" <> wrote in message news:<>...
    [discussion of what dtors should do snipped]
    > 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
     
    , Nov 18, 2004
    #14
  15. Timothy Madden

    pembed2003 Guest

    "Timothy Madden" <> wrote in message news:<>...
    >
    > 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.
     
    pembed2003, Nov 19, 2004
    #15
  16. "Timothy Madden" <> wrote in message
    news:<>...
    > 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 :
    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)
    ------------------------------------------------------------------------------
     
    Chris F Clark, Nov 19, 2004
    #16
  17. 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 :
    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)
    ------------------------------------------------------------------------------
     
    Chris F Clark, Nov 19, 2004
    #17
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. HyVong
    Replies:
    1
    Views:
    640
    Karl Seguin
    Nov 25, 2005
  2. Jacek Dziedzic

    sensing that an exception has occured

    Jacek Dziedzic, Jan 16, 2004, in forum: C++
    Replies:
    8
    Views:
    391
    Bob Bell
    Jan 18, 2004
  3. Replies:
    4
    Views:
    1,989
    James Kanze
    Nov 29, 2007
  4. Jeff
    Replies:
    1
    Views:
    1,236
    Mr. Arnold
    Jul 27, 2009
  5. glitteringsounds
    Replies:
    1
    Views:
    1,358
    Alf P. Steinbach /Usenet
    Jul 3, 2010
Loading...

Share This Page