Why Should Exceptions Be Used Conservatively

Why is exception handling bad?

Exceptions make it really easy to write code where an exception being thrown will break invariants and leave objects in an inconsistent state. They essentially force you to remember that most every statement you make can potentially throw, and handle that correctly. Doing so can be tricky and counter-intuitive.

Consider something like this as a simple example:

class Frobber
{
int m_NumberOfFrobs;
FrobManager m_FrobManager;

public:
void Frob()
{
m_NumberOfFrobs++;

m_FrobManager.HandleFrob(new FrobObject());
}
};

Assuming the FrobManager will delete the FrobObject, this looks OK, right? Or maybe not... Imagine then if either FrobManager::HandleFrob() or operator new throws an exception. In this example, the increment of m_NumberOfFrobs does not get rolled back. Thus, anyone using this instance of Frobber is going to have a possibly corrupted object.

This example may seem stupid (ok, I had to stretch myself a bit to construct one :-)), but, the takeaway is that if a programmer isn't constantly thinking of exceptions, and making sure that every permutation of state gets rolled back whenever there are throws, you get into trouble this way.

As an example, you can think of it like you think of mutexes. Inside a critical section, you rely on several statements to make sure that data structures are not corrupted and that other threads can't see your intermediate values. If any one of those statements just randomly doesn't run, you end up in a world of pain. Now take away locks and concurrency, and think about each method like that. Think of each method as a transaction of permutations on object state, if you will. At the start of your method call, the object should be clean state, and at the end there should also be a clean state. In between, variable foo may be inconsistent with bar, but your code will eventually rectify that. What exceptions mean is that any one of your statements can interrupt you at any time. The onus is on you in each individual method to get it right and roll back when that happens, or order your operations so throws don't effect object state. If you get it wrong (and it's easy to make this kind of mistake), then the caller ends up seeing your intermediate values.

Methods like RAII, which C++ programmers love to mention as the ultimate solution to this problem, go a long way to protect against this. But they aren't a silver bullet. It will make sure you release resources on a throw, but doesn't free you from having to think about corruption of object state and callers seeing intermediate values. So, for a lot of people, it's easier to say, by fiat of coding style, no exceptions. If you restrict the kind of code you write, it's harder to introduce these bugs. If you don't, it's fairly easy to make a mistake.

Entire books have been written about exception safe coding in C++. Lots of experts have gotten it wrong. If it's really that complex and has so many nuances, maybe that's a good sign that you need to ignore that feature. :-)

C++ - Arguments for Exceptions over Return Codes

I think this article sums it up.

Arguments for Using Exceptions

  1. Exceptions separate error-handling code from the normal program flow and thus make the code more readable, robust and extensible.
  2. Throwing an exception is the only clean way to report an error from a constructor.
  3. Exceptions are hard to ignore, unlike error codes.
  4. Exceptions are easily propagated from deeply nested functions.
  5. Exceptions can be, and often are, user defined types that carry much more information than an error code.
  6. Exception objects are matched to the handlers by using the type system.

Arguments against Using Exceptions

  1. Exceptions break code structure by creating multiple invisible exit points that make code hard to read and inspect.
  2. Exceptions easily lead to resource leaks, especially in a language that has no built-in garbage collector and finally blocks.
  3. Learning to write exception safe code is hard.
  4. Exceptions are expensive and break the promise to pay only for what we use.
  5. Exceptions are hard to introduce to legacy code.
  6. Exceptions are easily abused for performing tasks that belong to normal program flow.

C++ exception safety paranoia: how much is too much?

As all matters of engineering, it is about balance.

Certainly, const-ness/immutability and strong guarantees increase confidence in one's code (especially accompanied with tests). They also help trim down the space of possible explanations for a bug.

However, they might have an impact on performance.

Like all performance issues, I would say: profile and get rid of the hot spots. Copy And Swap is certainly not the only way to achieve transactional semantics (it is just the easiest), so profiling will tell you where you should absolutely not use it, and you will have to find alternatives.

How can we handle errors and exceptions in c like other languages(c++ and Java)?

Is there any way in C?

You dont do exception handling in C.

Just had this C Language Exception Handling as a work around I would say.

Typically C (as any old language) do manage such situation with error
code returned, possible errno setted and a table of string that
explain errno (sys_errlist). Thus a typical error management in C
require to test any error on functions that may returns error (almost
all standard libc functions) and, if error occur, manage it some way.

setjmp() and longjmp() functions


This article will describe what should/could be done in a exceptional
_C_ase. C language miss exception handling support and runtime, does not exists things like C++'s try.. catch, does not exist exception
class definition and hierarchy, but there are nice functions like
setjmp() and longjmp() that behave someway as try catch

#include <setjmp.h>
#include <stdio.h>
int
foo(int p)
{
if (p) siglongjmp(env,p); /* return to sigstejmp returning p */
return 0;
}

static sigjmp_buf env;
int
main() {
int a,r;
if (!(r=sigsetjmp(env, 1))) {
for (a=0; a<10; a++) {
fprintf(stdout,"%d\n",foo(a));
fflush(stdout);
}
} else {
fprintf(stdout,"exceptionally returned %d",r);
fflush(stdout);
}
}

sigsetjmp and siglongjmp are variant conforming to posix and compatible with bsd standard (see GNU Libc documentation)

... yes, it look like try{..}catch(..) in C++ except for the missing catch argument, and that there is only one level of exception

Error Handling in C:

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.

There is an external variable called "errno", accessible by the
programs after including <errno.h> - that file comes from the
definition of the possible errors that can occur in some Operating
Systems

Source reference



Related Topics



Leave a reply



Submit