When exceptions aren't enough: Dealing with runtime errors.

Discussion in 'C++' started by Aaron W. LaFramboise, Jul 24, 2005.

  1. I'm seeking a solution to my C++-life long dilemma of how to deal with
    errors when exceptions aren't appropriate. Below I highlight two
    error cases, which mainly occur when trying to handle "unexpected"
    errors on system interfaces. I am an experienced modern C++
    programmer, and I'm mainly interested in the case where the error is
    in a generic, reusable component where invasive control over the user
    is unacceptable.


    Case 1: An error was encountered, but this does not prevent continued
    execution.

    In these cases, it is generally inappropriate to throw an exception,
    and in some situations, due to the nature of the operation, it might
    be 'too late' (the operation has already been completed) or impossible
    (in a destructor) to throw an exception.

    For example, an error is encountered while trying to close a file.
    This most commonly happens for files with physical storage on remote
    filesystems. Depending on the situation, this may not be a serious
    condition by itself.

    Another example might be closing a temporary pipe at the completion of
    some sort of IPC operation. It may be the case that this failure is
    entirely irrelevent, and that execution can (and should) continue.
    Yet, the error should be reported, as it may have some relevence.


    Case 2: An error was encountered, and it probably will prevent
    continued execution.

    In these cases, we would like to throw an exception, but we can't,
    probably because we're in a destructor.

    An example of this would be a class that needs to allocate memory for
    some reason in its destructor, and this allocation fails.


    Solutions

    Well, I haven't found a good one.

    Traditional C solutions tend to involve doing something like writing
    to stderr, which is not appropriate in the general case for modern
    code.

    For many of the cases, we want stack-based processing similar to C++
    exceptions: we just don't want the part where it kills the current
    flow of execution. Resumptions would be perfect for many situations,
    yet there seems to be little interest in implementing these for C++.

    I'd speculate that this is a fairly common problem, and that it is
    fairly common to do the wrong thing, probably on the dubious
    nihilistic grounds that "we're screwed anyway" or "i don't care." How
    many times does code like this get written:

    my_file::~my_file() {
    close(file_handle); // not checking return value.. oh well
    }


    Has anyone found a good solution to these catagories of problems?


    Aaron W. LaFramboise
     
    Aaron W. LaFramboise, Jul 24, 2005
    #1
    1. Advertising

  2. Aaron W. LaFramboise

    Ian Guest

    Aaron W. LaFramboise wrote:
    > I'm seeking a solution to my C++-life long dilemma of how to deal with
    > errors when exceptions aren't appropriate. Below I highlight two
    > error cases, which mainly occur when trying to handle "unexpected"
    > errors on system interfaces. I am an experienced modern C++
    > programmer, and I'm mainly interested in the case where the error is
    > in a generic, reusable component where invasive control over the user
    > is unacceptable.
    >
    >
    > Case 1: An error was encountered, but this does not prevent continued
    > execution.
    >
    > In these cases, it is generally inappropriate to throw an exception,
    > and in some situations, due to the nature of the operation, it might
    > be 'too late' (the operation has already been completed) or impossible
    > (in a destructor) to throw an exception.
    >
    > For example, an error is encountered while trying to close a file.
    > This most commonly happens for files with physical storage on remote
    > filesystems. Depending on the situation, this may not be a serious
    > condition by itself.
    >
    > Another example might be closing a temporary pipe at the completion of
    > some sort of IPC operation. It may be the case that this failure is
    > entirely irrelevent, and that execution can (and should) continue.
    > Yet, the error should be reported, as it may have some relevence.
    >

    Log the error in an appropriate place, either you application's log file
    if it has one, or via you system's log interface.

    >
    > Case 2: An error was encountered, and it probably will prevent
    > continued execution.
    >
    > In these cases, we would like to throw an exception, but we can't,
    > probably because we're in a destructor.
    >
    > An example of this would be a class that needs to allocate memory for
    > some reason in its destructor, and this allocation fails.
    >

    In this case, either assert or throw an exception that is caught in
    main, printing a message and aborting.

    I prefer the former, at least on a platform where you can leave a core
    file for later analysis.

    Ian
     
    Ian, Jul 25, 2005
    #2
    1. Advertising

  3. Aaron W. LaFramboise

    Guest

    Aaron W. LaFramboise wrote:
    >..
    >Case 1: An error was encountered, but this does not prevent
    >continued execution.
    >In these cases, it is generally inappropriate to throw an
    >exception, and in some situations, due to the nature of the
    >operation, it might be 'too late' (the operation has already
    >been completed) or impossible (in a destructor) to throw an
    >exception.


    >For example, an error is encountered while trying to close a
    >file. This most commonly happens for files with physical
    >storage on remote filesystems. Depending on the situation,
    >this may not be a serious condition by itself.


    I have a developing library, which tries to solve problems
    like you mentioned.

    http://sourceforge.net/projects/libwx/

    Hope it could help. Suggestion and relevant questions are
    welcome. IMHO(from articles there), "close" stuff has to
    succeed, no matter what it returned.

    >Case 2: An error was encountered, and it probably will
    >prevent continued execution. In these cases, we would like
    >to throw an exception, but we can't, probably because we're
    >in a destructor. An example of this would be a class that
    >needs to allocate memory for some reason in its destructor,
    >and this allocation fails.


    It is thought as class design problem, see also the suggested
    link.
     
    , Jul 25, 2005
    #3
  4. On Mon, 25 Jul 2005 12:01:54 +1200, Ian <> wrote:

    >Aaron W. LaFramboise wrote:


    >> Case 1: An error was encountered, but this does not prevent continued
    >> execution.
    >>

    >Log the error in an appropriate place, either you application's log file
    >if it has one, or via you system's log interface.


    If I am writing a reusable file-handling component, for example, it is
    the likely case that the component has no idea what the correct place
    is. For example, if you were re-implementing something similar to
    std::filebuf, how would you know how to report errors from ~filebuf?

    Notice that the standard cleverly (or not) avoids this problem by
    ignoring the cause of errors in general (There is no standard way to
    find out why filebuf::eek:pen() failed, for example.), and ignoring
    failures in close() in the destructor in particular.


    >> Case 2: An error was encountered, and it probably will prevent
    >> continued execution.
    >>

    >In this case, either assert or throw an exception that is caught in
    >main, printing a message and aborting.


    You can't throw from a destructor. assert() is not acceptable because
    this is a runtime error, not a logic error. The application should be
    able to exit gracefully. A core file is not helpful here, because
    there is no bug.


    Aaron W. LaFramboise
     
    Aaron W. LaFramboise, Jul 25, 2005
    #4
  5. Aaron W. LaFramboise

    Ian Guest

    Aaron W. LaFramboise wrote:
    > On Mon, 25 Jul 2005 12:01:54 +1200, Ian <> wrote:
    >
    >
    >>Aaron W. LaFramboise wrote:

    >
    >
    >>>Case 1: An error was encountered, but this does not prevent continued
    >>>execution.
    >>>

    >>
    >>Log the error in an appropriate place, either you application's log file
    >>if it has one, or via you system's log interface.

    >
    >
    > If I am writing a reusable file-handling component, for example, it is
    > the likely case that the component has no idea what the correct place
    > is. For example, if you were re-implementing something similar to
    > std::filebuf, how would you know how to report errors from ~filebuf?
    >

    You could, for your own errors, use a static error member?

    > Notice that the standard cleverly (or not) avoids this problem by
    > ignoring the cause of errors in general (There is no standard way to
    > find out why filebuf::eek:pen() failed, for example.), and ignoring
    > failures in close() in the destructor in particular.
    >
    >
    >
    >>>Case 2: An error was encountered, and it probably will prevent
    >>>continued execution.
    >>>

    >>
    >>In this case, either assert or throw an exception that is caught in
    >>main, printing a message and aborting.

    >
    >
    > You can't throw from a destructor. assert() is not acceptable because
    > this is a runtime error, not a logic error. The application should be
    > able to exit gracefully. A core file is not helpful here, because
    > there is no bug.
    >

    Well you could if there wasn't anything else to do. With assert, the
    error condition could be something outside of the code's control, maybe
    a problem with the underlying operating system. So one of the code's
    assumptions is false, which is fair grounds for an assert.

    Ian
    >
    > Aaron W. LaFramboise
    >
     
    Ian, Jul 25, 2005
    #5
    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. Guest
    Replies:
    1
    Views:
    573
    Lowell Heddings
    Dec 9, 2004
  2. Leo Breebaart

    How to name Exceptions that aren't Errors

    Leo Breebaart, Apr 7, 2005, in forum: Python
    Replies:
    12
    Views:
    627
    Christos TZOTZIOY Georgiou
    Apr 15, 2005
  3. John Nagle
    Replies:
    11
    Views:
    520
    John Nagle
    Apr 27, 2007
  4. William McBrine
    Replies:
    1
    Views:
    466
    Tim Golden
    Mar 16, 2008
  5. yawnmoth
    Replies:
    97
    Views:
    4,727
    Bent C Dalager
    Feb 27, 2009
Loading...

Share This Page