Exceptions vs. Error Codes

Discussion in 'C++' started by Shane Groff, Oct 10, 2004.

  1. Shane Groff

    Shane Groff Guest

    I know this is a recurring discussion (I've spent the last 3 days
    reading through threads on the topic), but I feel compelled to start
    it up again.

    After reading through the existing threads, I find myself convinced
    that exceptions are a better mechanism, for example because
    constructors and operators can't return errors, and code that doesn't
    need to handle/translate/recover in the face of errors, but can just
    propagate the error is cleaner with exceptions.

    However, those reasons are often not compelling enough to convince
    people who don't like exceptions (usually in my experience because
    they incorrectly think that exceptions are more 'dangerous' somehow
    than error codes, when in fact, they just don't see that it is just as
    dangerous to ignore an error code as it is to not handle an exception
    when it should be).

    Consider this idiom when using error codes:

    ErrorCode EcFoo()
    {
    ErrorCode ec;
    Check(EcBar());
    Check(EcBletch());
    ...
    Exit:
    return (ec);
    }

    Here, Check is a macro that checks the return code and jumps to Exit
    if an error occurs.

    Using this pattern, we avoid the appearance of a slew of if/then
    statments (although they are there, of course, just hidden by the
    preprocessor).

    This makes the code almost as straightforward as the exception case,
    and doesn't introduce much overhead (space or time), since it is
    basically just adding a check for 0 to each call.

    This addresses some of the problems I've seen leveled against error
    codes. Although it seems to me that we're just writing what amounts to
    our own equivalent to exceptions here (for example, functions that
    don't handle the error don't need to do any 'additional' work to
    propagate the error, assuming they are following the pattern), some
    people are more comfortable with this because they know that returning
    and checking for error codes is always fairly inexpensive, while
    throwing an exception can be expensive.

    Any specific thoughts on the idiom, or compelling arguments to offer
    for the use of exceptions to the reluctant?
     
    Shane Groff, Oct 10, 2004
    #1
    1. Advertising

  2. Shane Groff

    Mike Wahler Guest

    "Shane Groff" <> wrote in message
    news:...
    > I know this is a recurring discussion (I've spent the last 3 days
    > reading through threads on the topic), but I feel compelled to start
    > it up again.
    >
    > After reading through the existing threads, I find myself convinced
    > that exceptions are a better mechanism, for example because
    > constructors and operators can't return errors, and code that doesn't
    > need to handle/translate/recover in the face of errors, but can just
    > propagate the error is cleaner with exceptions.
    >
    > However, those reasons are often not compelling enough to convince
    > people who don't like exceptions (usually in my experience because
    > they incorrectly think that exceptions are more 'dangerous' somehow
    > than error codes, when in fact, they just don't see that it is just as
    > dangerous to ignore an error code as it is to not handle an exception
    > when it should be).
    >
    > Consider this idiom when using error codes:
    >
    > ErrorCode EcFoo()
    > {
    > ErrorCode ec;
    > Check(EcBar());
    > Check(EcBletch());
    > ...
    > Exit:
    > return (ec);
    > }
    >
    > Here, Check is a macro that checks the return code and jumps to Exit
    > if an error occurs.
    >
    > Using this pattern, we avoid the appearance of a slew of if/then
    > statments (although they are there, of course, just hidden by the
    > preprocessor).
    >
    > This makes the code almost as straightforward as the exception case,
    > and doesn't introduce much overhead (space or time), since it is
    > basically just adding a check for 0 to each call.
    >
    > This addresses some of the problems I've seen leveled against error
    > codes. Although it seems to me that we're just writing what amounts to
    > our own equivalent to exceptions here (for example, functions that
    > don't handle the error don't need to do any 'additional' work to
    > propagate the error, assuming they are following the pattern), some
    > people are more comfortable with this because they know that returning
    > and checking for error codes is always fairly inexpensive, while
    > throwing an exception can be expensive.
    >
    > Any specific thoughts on the idiom, or compelling arguments to offer
    > for the use of exceptions to the reluctant?


    One obvious disadvantage of your 'error code' solution is that
    it doesn't implement 'stack unwinding' i.e. automatic destruction,
    whereas exceptions do.

    -Mike
     
    Mike Wahler, Oct 10, 2004
    #2
    1. Advertising

  3. * Shane Groff:
    > I know this is a recurring discussion (I've spent the last 3 days
    > reading through threads on the topic), but I feel compelled to start
    > it up again.
    >
    > After reading through the existing threads, I find myself convinced
    > that exceptions are a better mechanism, for example because
    > constructors and operators can't return errors


    Constructors can produce error codes. A constructor can take a reference
    or pointer argument, or it can store an error code somewhere else. One
    main reason why that is not a _good idea_ is that the built-in mechanism
    for cleaning up when an objected is allocated dynamically and the
    constructor fails, requires an exception from the constructor, and that
    similar techniques implemented by oneself have the same requirement; without
    such automated cleanup there is a live but invalid object around.

    Another main reason is that the approach is not general: additional arguments
    cannot be tacked on to a copy constructor or, as you write, an operator, so
    these would have to store their error codes in some accessible place.

    The "live but invalid" argument is also the main argument for not using
    two-phase construction (except when encapsulated by an object factory).


    > and code that doesn't
    > need to handle/translate/recover in the face of errors, but can just
    > propagate the error is cleaner with exceptions.


    Yup.


    > However, those reasons are often not compelling enough to convince
    > people who don't like exceptions (usually in my experience because
    > they incorrectly think that exceptions are more 'dangerous' somehow
    > than error codes, when in fact, they just don't see that it is just as
    > dangerous to ignore an error code as it is to not handle an exception
    > when it should be).
    >
    > Consider this idiom when using error codes:
    >
    > ErrorCode EcFoo()
    > {
    > ErrorCode ec;
    > Check(EcBar());
    > Check(EcBletch());
    > ...
    > Exit:
    > return (ec);
    > }
    >
    > Here, Check is a macro that checks the return code and jumps to Exit
    > if an error occurs.


    Macros are evil.

    An alternative is to make the error code an object that requires a check()
    or value() or succeeded() call or something in order not to throw an
    exception.

    Some folks have advocated that approach e.g. because it makes the code more
    explicit; one main drawback is that all code everywhere must then check every
    function call for possible error, giving C-style impenetrable code, and
    another main drawback is that exceptions are needed for constructors and
    such anyway, lest one wind up with "live but invalid" objects...

    --
    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?
     
    Alf P. Steinbach, Oct 10, 2004
    #3
  4. Shane Groff

    Shane Groff Guest

    "Mike Wahler" <> wrote in message news:<z90ad.758$>...
    > "Shane Groff" <> wrote in message
    > news:...
    > > Consider this idiom when using error codes:
    > >
    > > ErrorCode EcFoo()
    > > {
    > > ErrorCode ec;
    > > Check(EcBar());
    > > Check(EcBletch());
    > > ...
    > > Exit:
    > > return (ec);
    > > }
    > >
    > > Here, Check is a macro that checks the return code and jumps to Exit
    > > if an error occurs.
    > >
    > >
    > > Any specific thoughts on the idiom, or compelling arguments to offer
    > > for the use of exceptions to the reluctant?

    >
    > One obvious disadvantage of your 'error code' solution is that
    > it doesn't implement 'stack unwinding' i.e. automatic destruction,
    > whereas exceptions do.
    >
    > -Mike


    I'm not sure I understand. If I have local objects within the
    function, they will be destroyed when the function exists whether the
    exit is through a normal return, or an exception. If every function
    is written along the pattern above, then each function jumps to the
    return and passes the error code back up the chain, and local objects
    are destroyed when the function returns.
     
    Shane Groff, Oct 10, 2004
    #4
  5. "Shane Groff" <> wrote in message
    news:...
    >I know this is a recurring discussion (I've spent the last 3 days
    > reading through threads on the topic), but I feel compelled to start
    > it up again.
    >
    > After reading through the existing threads, I find myself convinced
    > that exceptions are a better mechanism, for example because
    > constructors and operators can't return errors, and code that doesn't
    > need to handle/translate/recover in the face of errors, but can just
    > propagate the error is cleaner with exceptions.
    >
    > However, those reasons are often not compelling enough to convince
    > people who don't like exceptions (usually in my experience because
    > they incorrectly think that exceptions are more 'dangerous' somehow
    > than error codes, when in fact, they just don't see that it is just as
    > dangerous to ignore an error code as it is to not handle an exception
    > when it should be).


    I think your reasoning is spot on. I've seem many examples where code
    appears to be checking for errors because there are loads of if statements
    checking return values (often this is the bulk of the code!) but when you
    actually test it doesn't work because somewhere in the chain of function
    calls a return value check was missed, or because the code has been hacked
    around the cleanup after detecting an error doesn't work correctly.

    >
    > Consider this idiom when using error codes:
    >
    > ErrorCode EcFoo()
    > {
    > ErrorCode ec;
    > Check(EcBar());
    > Check(EcBletch());
    > ...
    > Exit:
    > return (ec);
    > }
    >
    > Here, Check is a macro that checks the return code and jumps to Exit
    > if an error occurs.


    In C++ you are not allowed to jump over a declaration. So this would force
    you into C style code where all the declarations are at the start of a
    block.

    john
     
    John Harrison, Oct 10, 2004
    #5
  6. Shane Groff

    Michael Kurz Guest

    "Shane Groff" <> schrieb im Newsbeitrag
    news:...
    > "Mike Wahler" <> wrote in message

    news:<z90ad.758$>...
    > > "Shane Groff" <> wrote in message
    > > news:...
    > > > Consider this idiom when using error codes:
    > > >
    > > > ErrorCode EcFoo()
    > > > {
    > > > ErrorCode ec;
    > > > Check(EcBar());
    > > > Check(EcBletch());
    > > > ...
    > > > Exit:
    > > > return (ec);
    > > > }
    > > >
    > > > Here, Check is a macro that checks the return code and jumps to Exit
    > > > if an error occurs.
    > > >
    > > >
    > > > Any specific thoughts on the idiom, or compelling arguments to offer
    > > > for the use of exceptions to the reluctant?

    > >
    > > One obvious disadvantage of your 'error code' solution is that
    > > it doesn't implement 'stack unwinding' i.e. automatic destruction,
    > > whereas exceptions do.


    >
    > I'm not sure I understand. If I have local objects within the
    > function, they will be destroyed when the function exists whether the
    > exit is through a normal return, or an exception. If every function
    > is written along the pattern above, then each function jumps to the
    > return and passes the error code back up the chain, and local objects
    > are destroyed when the function returns.


    You are right. The stackunwinding is only needed when you throw an exception
    somewhere several levels deep in a callstack and the exception hanling need
    to unwind all these calls in progress. In your sample this is not a problem.
    I think goto would not allow this anyway.


    Regards
    Michael
     
    Michael Kurz, Oct 10, 2004
    #6
  7. Shane Groff

    Michael Kurz Guest

    "Shane Groff" <> schrieb im Newsbeitrag
    news:...
    >
    > Consider this idiom when using error codes:
    >
    > ErrorCode EcFoo()
    > {
    > ErrorCode ec;
    > Check(EcBar());
    > Check(EcBletch());
    > ...
    > Exit:
    > return (ec);
    > }
    >
    > Here, Check is a macro that checks the return code and jumps to Exit
    > if an error occurs.
    >
    > Using this pattern, we avoid the appearance of a slew of if/then
    > statments (although they are there, of course, just hidden by the
    > preprocessor).
    >
    > This makes the code almost as straightforward as the exception case,
    > and doesn't introduce much overhead (space or time), since it is
    > basically just adding a check for 0 to each call.
    >
    > This addresses some of the problems I've seen leveled against error
    > codes. Although it seems to me that we're just writing what amounts to
    > our own equivalent to exceptions here (for example, functions that
    > don't handle the error don't need to do any 'additional' work to
    > propagate the error, assuming they are following the pattern), some
    > people are more comfortable with this because they know that returning
    > and checking for error codes is always fairly inexpensive, while
    > throwing an exception can be expensive.
    >
    > Any specific thoughts on the idiom, or compelling arguments to offer
    > for the use of exceptions to the reluctant?


    I have seen these kind of error handling many times in code, but somehow I
    never liked the necessary goto statement.
    So I never used it myself.

    When I have to decide if I should use exception handling or error codes I
    have mostly the following things in mind:
    - Error codes are self documenting whereas exceptions are not.
    - Exceptions are slower so if its within performance critical code I dont
    want to open a try/catch block all the time.
    - Exception lead to a cleaner caller code.
    - C++ constructs throw exceptions themselfes (new) so If not using
    exceptions as error communication these should be converted to error codes
    or avoided (hard to achieve), which is quite an effort and a possible
    performance problem again .
    - Make code (caller) exception safe requires some knowledge. After reading
    Herb Sutters "Exceptional C++" I wondered why my programs ever worked
    properly ;-)


    IMHO at the end its a mixture of the requirements your code has to foolfill
    and a bit of personal taste.



    Best Regards
    Michael
     
    Michael Kurz, Oct 10, 2004
    #7
  8. Shane Groff

    Michael Kurz Guest

    "Michael Kurz" <> schrieb im Newsbeitrag
    news:416902db$...
    >
    > IMHO at the end its a mixture of the requirements your code has to

    foolfill

    sorry, meant fulfill of course. :)
     
    Michael Kurz, Oct 10, 2004
    #8
  9. Shane Groff

    Mike Wahler Guest

    "Shane Groff" <> wrote in message
    news:...
    > "Mike Wahler" <> wrote in message news:<z90ad.758
    > > One obvious disadvantage of your 'error code' solution is that
    > > it doesn't implement 'stack unwinding' i.e. automatic destruction,
    > > whereas exceptions do.
    > >
    > > -Mike

    >
    > I'm not sure I understand. If I have local objects within the
    > function, they will be destroyed when the function exists whether the
    > exit is through a normal return, or an exception. If every function
    > is written along the pattern above, then each function jumps to the
    > return and passes the error code back up the chain, and local objects
    > are destroyed when the function returns.


    Right. But with exceptions, you don't need to write anything.
    Just throw the exception and it 'just works'.

    -Mike
     
    Mike Wahler, Oct 10, 2004
    #9
    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. Greg  --
    Replies:
    4
    Views:
    2,240
  2. Replies:
    2
    Views:
    2,933
    Malcolm
    Aug 20, 2005
  3. mike3
    Replies:
    14
    Views:
    619
  4. Allen
    Replies:
    1
    Views:
    676
    Mark Rae [MVP]
    Dec 3, 2007
  5. mike3
    Replies:
    135
    Views:
    2,058
    gremnebulin
    Jun 20, 2012
Loading...

Share This Page