Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a general consensus in the C++ community on when exceptions should be used? [closed]

I just spent a few hours reading through SO questions on the topic of when to use exceptions, and it seems like there are two camps with different point of views:

  1. Use exceptions over error codes
  2. Use error codes most of the time, and exceptions only when some catastrophic error occurs

Is this just a controversial topic with no widely accepted best practice?

like image 600
pepsi Avatar asked Apr 10 '11 03:04

pepsi


People also ask

Should exception handling be used in all circumstances?

Although structured exception handling is the recommended way of handling error conditions, make sure you use exceptions only in exceptional circumstances when error conditions occur.

When should exception handling be used?

Exceptions should be used for situation where a certain method or function could not execute normally. For example, when it encounters broken input or when a resource (e.g. a file) is unavailable. Use exceptions to signal the caller that you faced an error which you are unwilling or unable to handle.

Does C language have exception handling?

C does not provide direct support for error handling (also known as exception handling). By convention, the programmer is expected to prevent errors from occurring in the first place, and test return values from functions.

How do you handle exceptions in C programming?

As such, C programming does not provide direct support for error handling but being a system programming language, it provides you access at lower level in the form of return values. Most of the C or even Unix function calls return -1 or NULL in case of any error and set an error code errno.


2 Answers

As you can probably gather from the wealth of answers, there is certainly no consensus.

Semantically, exceptions and error provide the exact same functionality. Indeed they are identical in about all semantic aspects, and errors can be arbitrarily enriched much like exceptions (you don't have to use a simple code, you can use a real bundle of data!).

The only difference there is is their propagation methods:

  • errors have to be passed down manually
  • exceptions are propagated automatically

On the other hand:

  • the possibility of an error is perfectly documented in the signature
  • exceptions are silent on code inspection (read GotW #20: Code Complexity and cry) and hidden paths of execution make reasoning harder.

The very reason both solutions can appear clunky is simply that error checking is difficult. Indeed most of the code I am writing daily concerns error checking, whether technical or functional.

So what to do ?

Warning: demonstration ahead, jump over to the next section if you care only for an answer

I personally like to leverage the type system here. The typical example is the pointer-reference dichotomy: a pointer is like a reference that can be null (and reseated, but it does not matter here)

Therefore, instead of:

// Exceptions specifications are better not used in C++ // Those here are just to indicate the presence of exceptions Object const& Container::search(Key const& key) const throw(NotFound); 

I will tend to write:

Object const* Container::search(Key const& key) const; 

Or better yet, using clever pointers:

Pointer<Object const> Container::search(Key const& key) const;  template <typename O> O* Pointer<O>::operator->() const throw(Null);  template <typename O> O& Pointer<O>::operator*() const throw(Null); 

Here I find the use of exception superfluous for 2 reasons:

  • If we are searching for an object, then there not finding it is both a perfectly common occurrence and there is not much data to carry about: cause of error ? it is not there
  • The client does not necessarily consider it an error that it is not there, who am I to assume that I know her business better than she does ? Who am I to decide that there will never be a case where it won't be appropriate not to find what was asked for ?

I don't have a problem with exceptions per se, but they can make the code awkward, consider:

void noExceptions(Container const& c) {   Pointer<Object const> o = c.search("my-item");    if (!o) {     o = c.search("my-other-item");   }    if (!o) { return; } // nothing to be done    // do something with o } 

And compare it with the "exception" case:

void exceptions(Container const& c) {   Object const* p = 0;   try {     p = &c.search("my-item");   }   catch(NotFound const&) {     try {       p = &c.search("my-other-item");     }     catch(NotFound const&) {       return; // nothing to be done     }   }    // do something with p } 

In this case, the use of exceptions does not seem appropriate :/

On the other hand:

try {  print() << "My cute little baby " << baby.name() << " weighs " << baby.weight(); } catch(Oupsie const&) {   // deal } 

is certainly more appealing than:

if (!print("My cute little baby ")) { /*deal*/ } if (!print(baby.name())) { /*deal*/ } if (!print(" weighs ")) { /*deal*/ } if (!print(baby.weight())) { /*deal*/ } 

What is the best then ?

It depends. Like all engineering problem there is no silver bullet, it's all about concessions.

So keep 2 things in mind:

  • Error reporting is part of the API
  • APIs should be designed with ease of use in mind

If you find yourself wondering whether to use an exception or not, just try to use your API. If there is no clear cut winner, it is just that: there is no ideal solution.

Oh, and do not hesitate to refactor your API when it becomes clear that the error reporting mechanism elected at the time of crafting it is no longer appropriate. Don't be ashamed: requirements change with time, so it is normal that the API change with them.

Personally I tend to use exceptions for unrecoverable errors only: I therefore have few try/catch in my code, only in the outermost levels, to accurately log the error (love stack frames) and log a dump of the BOM as well.

This is very similar (and indeed strongly influenced) by Haskell, the code there is seggregated in two clear cut parts: while any can throw exceptions, only the IO part (the extern one) may actually catch them. Therefore, the pure part must deal with error conditions with other ways in case they are "normal".

If, however, I am faced with a problem where using an exception makes the code easier to read and more natural (which is subjective) then I use an exception :)

like image 171
Matthieu M. Avatar answered Sep 20 '22 11:09

Matthieu M.


I don't think this is a discussion which is exclusive to the C++ community, but here are two high-level guidelines which have helped me:

  1. Throw exceptions only in exceptional circumstances. It sounds obvious, but many APIs get built with exceptions being thrown about 50% of the time they are called (and a boolean return status would have been more appropriate).
  2. In your catch clauses, know when to consume exceptions, when to rethrow them as-is and when to throw a different type of exception instead. I can't give you a one-size-fits-all rule for this because it's so dependent on your application's needs, but if you take one thing away from this it should be that the silent consumption of an exception might be the worst thing your code could do. Each frame should have some knowledge of what the calling frame(s) expects when things go wrong.
like image 34
Brian Kelly Avatar answered Sep 20 '22 11:09

Brian Kelly