Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C++ (http://www.go4expert.com/articles/cpp-tutorials/)
-   -   Exceptions Vs setjmp (http://www.go4expert.com/articles/exceptions-vs-setjmp-t16509/)

jayaraj_ev 11Mar2009 16:06

Exceptions Vs setjmp
 

Introduction



Exception handling is a mechanism when a part of code detects exceptional suituation, it seperates the code where it detects and handles it seperately.

This mechanism can be done differently in C and C++, ie eigther using setjmp()&longjmp() or Exception in c++ try/catch(...).

setjmp/longjmp



setjmp(jmp_buf env) saves the current program environment of callee in jmp_buf structure for later use. The type jmp_buf is defined in <setjmp.h>. it returns 0 when called the first time.It returns a non zero if it was called from a call to longjmp().

longjmp(jmp_buf env,int val ) sets the context of the environment back the way it was when the setjmp() was invoked moves the Program counter to point back to setjmp(). This time, when the "setjmp" returns, the value it returns is the value specified in the call to longjmp.If the value passed to longjmp is 0 then setjmp will return as 1 not 0.

Pros/Cons



1.If the function in which setjmp() was called returns normally and longjmp() with the corresponding jmp_buf object is called then longjmp() restores the stack pointer of the stack frame which is invalidated when the function returns normally, where stack pointer would point to a non-existent and potentially overwritten/corrupted stack frame. To solve this most implementations of longjmp() leave the stack frame intact, allowing setjmp() and longjmp() to be used to jump back-and-forth between two or more functions.

Code:

#include <stdio.h>
#include <setjmp.h>

static jmp_buf env;

int fn(void)
{
  int j = 3;
  int i = setjmp(env);
  if (i == 0)
  {
    j = 4;
    printf("fn called \n");
  }
  printf("fn() j = %d\n",j);
  return i;
}

int main (void)
{
 
  if (fn() == 0)
  {
    printf("fn calling \n");   
    longjmp(env, 1);
  }
 
  return 0;
}

2. A problem with the use of setjmp/longjmp is that cleanup (such as closing file descriptors, flushing buffers, freeing heap-allocated memory, etc.) is not conducted automatically.
Which is handled in exceptions in c++ called Stack Unwinding.

Code:

#include <iostream>
#include <setjmp.h>

using namespace std;

static jmp_buf env;
class A
{
  public :
    A()
    {
      cout<<"calling cons A()"<<endl;
    }
    ~A()
    {
      cout<<"calling des ~A()"<<endl;
    }
};

int main (void)
{
  A a;
  if (setjmp(env) != 0)
  {
    return 0;
  }
  longjmp(env,1);
  return 0;
}

Exceptions



In an exceptional situation, you can throw a object called an exception object, which can be dealed with a designated block of code in a direct or indirect caller of the function that threw the exception. This block of code is called a handler where you specify the types of exceptions to get processed. A handler can also rethrow an exception so it can be caught by another handler.

Try blocks



Try block are the areas in your program where you want to govern the exceptions thrown and you want to handle them immediately.

Different ways of representing them as

Code:

void fn() try
{
  //Fn definition
}
catch (...)
{
}

Constructor() try : Initializationlist()
{
}
catch(...)
{
}

try
{
  fn();
}
catch(...)
{

}

Nested try blocks



When you have nested try blocks and throw occurs with a exception X in a function called by an inner try block, control is transferred to outward catch till the first catch block is found whose argument matches the argument of the throw expression.

Code:

try
{
  try
  {
      throw X;
  }
  catch(Y)
  {
  }
}
catch(X)
{
}

Catch Blocks



The Handler to catch exceptions of different objects are defined below try blocks.You can catch exception of fundamental types(like int, char, etc...), base and derived class objects, references, const, volatile and pointers to all of above types.But cannot use trype that are incomplete where u can't know the size (like void *).

catch(...) the ellipse in the catch brackets mention that you can catch exceptions of any type thrown.A handler may rethrow an exception so it can be caught by another handler.when the catch doesn't catch the exception it finally calls terminate().

You can set this terminate function with your own function using set_terminate(func) where func is void func(void){ }

Throw


You use a throw expression to mention that your program has encountered an exception.If you throw a object, then call it with a constructor like throw A(int i, int j) or else with object that is already created; You can always rethrow an exception from a catch block if you are not able to handle it.

Code:

void fn(void) try
{
}
catch(...)
{
  not able to handle here.
  throw;
}

try
{
  fn();
}
catch (...)
{
  handled here.
}

You can also specify the type of exceptions that a function can throw like:
void function(void) throw(int, char);
void (*functionPtr)(void) throw(Exception);
void function(void fn(void) throw(int));

void function(void) throw() It means no exception is ment to be throw out this function. if you throw one then it will call unexcepted.

If the function throws a Exception which is not specified then it calls unexpected().


Stack Unwinding


If an exception is thrown from a try block to a handler, the C++ run time calls destructors of all automatic objects constructed inside the try block. This process is called stack unwinding.The automatic objects are destroyed in reverse order of their construction.

Actually what happens is the stack frame created inside the try block gets released / poped out.So it calls allthe destructors of the objects.But in case of setjmp/longjmp it doesn't happen because the stack frame is intact so that we can make a jump froth and back to the frame by long jmp.

Code:

class A
{
  public:
    A()
    {
      cout<<"cons A"<<endl;
     
    }
    ~A()
    {
      cout<<"des A"<<endl;
      throw 'a'; //will be called by the terminate fn.
    }
};


void fn(void)
{
  cout<<"my treminated"<<endl;
  return;
}

int main(void)
{
  set_terminate(fn); //to set unexpected handling use set_unexpected(fn);
  try
  {
    A a;
    throw 'a';
  }
  catch(char i)
  {
    cout<<"Exception in Main"<<endl;
  }
  return 0;
}

Cons



Do you know why Embedded systems don't use Exceptions ?

1. Because the foot print for each stack frame created becomes more when we use Exception as it needs to store some info them stack unwinding. In embedded systems Memory restrictions.
2. As the time required for Exception handling is not determined because . the Stack unwinding leads to destroying of the objects created inside the block so thetiime to handle the exception is not know. here we have time constrains.

thanks & regards,
jayaraj

shabbir 6Apr2009 15:02

Re: Exceptions Vs setjmp
 
Article of the month competition nomination started here

MHpurple 6Apr2009 20:07

Re: Exceptions Vs setjmp
 
you only suggest one

LenoxFinlay 18Jul2009 10:40

Re: Exceptions Vs setjmp
 
Exception are a very powerful way to program error safe programs. Exceptions let you write straight code without testing for errors at each statement. In modern programming languages, such as C++, Java or C#, exceptions are expressed with the try-throw-catch
statement. ANSI-C provide a lot of functions: math functions ( statement.log, sqrt...), string handling functions (strdup, strcmp, ...) and I/O functions (getc, printf, ...). All these functions are widely used and simple to understand (...strtok is not so intuitive after all...): only two functions are considered strange beasts.


All times are GMT +5.5. The time now is 18:02.