HP C++ User Documentation

 

HP C++

HP C++
Using HP C++ for Tru64 UNIX and Linux Alpha


Previous Contents Index


Chapter 8
Handling Exceptions

C++ incorporates an exception mechanism for handling unusual program events (not necessarily just errors). Exception handling enables you to detect program events and to provide handlers to deal with the events.

HP C++ implements the exception handling model described in the International C++ Standard.

This chapter provides a brief introduction to exception handling, describes the run-time considerations of exception handling in HP C++, and recommends ways to use exception handlers for optimum performance. For a detailed description of C++ exception handling in general, see Chapter 14 in The C++ Programming Language, 3rd Edition.

Readers of this chapter should be familiar with the C++ exception-handling terminology, such as throwing and catching exceptions.

For information on debugging programs with exception handlers, see the HP Tru64 UNIX Ladebug Debugger Manual, which is included with the operating system documentation.

8.1 Structure

The following example shows the basic structure for declaring and using exception handlers in C++:


    .
    .
    .
void might_break(int i) 
{ 
    if (i == 1) throw "something!"; 
    if (i == 4) throw 4; 
    // ...
} 
 
void p (int i) 
{                                //        
    try                          //        begin try block 
    {                            //        
        might_break(i);          //        
    }                            //        
    catch (const char *p)        //        begin handler 
    {                            //         . 
        cout << "caught " << p;  //         . 
        // fix whatever...       //         . 
    }                            //        end try block 
}                                //        end handler 
    .
    .
    .

In this example, calling p with a value of anything other than 1 or 4 causes the program to execute normally, with no exception thrown. If p is called with a value of 1, the might_break function throws a string object to the p handler, which prints caught something! .

If p is called with 4, an int is thrown. Because p cannot catch values of type int , the search for a handler proceeds up the call stack until an appropriate handler can be found. If nothing on the stack can handle an int , program execution terminates immediately after calling the std::terminate function.

C++ exception handling represents a termination model, which means that program execution never proceeds past a throw . For additional information, see the C++ International Standard.

8.2 Run-Time Considerations

HP C++ optimizes the implementation of exception handling for normal execution, as follows:

  • As much as possible, the overhead for exceptions is incurred when throwing an exception.
  • Applications that have try blocks and that run without causing exceptions incur only slight overhead as follows:
    • The size of an executable image increases 3 x 128 bits for a simple try-catch block because of tables that describe the handlers.
    • When entering or exiting a handler, the frame number is saved to be used for finding any exception raised.

Some functions without explicit handlers may have implicit handlers. The compiler creates a handler for each automatic object that has a destructor. The compiler also creates handlers for constructors that initialize subobjects that have destructors. In such a constructor, the compiler creates a handler for each member with a destructor, and a handler for each base class with a destructor.

The -nocleanup option suppresses generation of such implicit handlers, which results in a slightly smaller executable file. Use the -nocleanup option for programs that do not use exception handling or do not require destruction of automatic objects during exception processing.

8.3 Coding Recommendations

Some recommendations for optimal results when using exception handling in HP C++ are:

  • Use destructors where necessary, but avoid creating them where they are not useful.
    The existence of a destructor can cause the compiler to create an implicit exception handler --- as in the example of an implicit exception handler for an automatic object with a destructor.
  • Use fewer and larger try blocks, instead of many small try blocks, wherever possible.
    Whereas a single try block with several handlers may improve performance compared to several small try blocks with one handler each, the improvement may not always be enough to justify making awkward changes to your program logic.

8.4 Mixed-Language Applications

When C functions are intermixed with C++ functions, the compiler treats them as C++ functions without exception handlers. The C functions can have their own exception handlers. Each function within a program can point to its own language-specific handler.

8.5 Finding Information about Exceptions

To obtain more information about an exception that was thrown, you can call the function __cxx_exception_info from a catch(...) clause.

The function returns the system_exrec_type defined in excpt.h , which points to the facility that raised the exception and to other information.

The prototype is found in cxx_exception.h and is:


system_exrec_type *__cxx_exception_info(); 

For more information about the system_exrec_type , see the excpt reference page.

8.6 Using the dlclose Routine

The dlclose routine cannot be used to delete a shared object ( .so ) until after any handlers handling an exception, thrown from the shared object, have exited. This restriction is necessary because, when exiting from a handler, the C++ exception support needs to reference data structures that were defined at the throw point.

8.7 Catching Signals and C Exceptions

HP Tru64 UNIX and Linux Alpha report divides by zero and other "bad behavior" by libc as signals. To manage signals, you can install a signal handler.

If you want C exceptions, you can install exc_raise_signal_exception as the handler for particular signals. When a signal occurs, a C exception is thrown.

Although C++ catch clauses ( catch(...) ) recognize C exceptions, the exceptions are not coverted to exception as defined in <exception> .

Consider the following example:


#include <stdlib.h> 
#include <excpt.h> //new 
#include <signal.h> //new 
struct sigaction foo =   //new 
 {(void (*)(int))exc_raise_signal_exception,0,0}; // new 
 
#include <iostream.h> 
#include <exception> 
 
int main() 
{ 
  double x, y, z; 
 
  sigaction(SIGFPE,&foo,0); //new 
 
  cerr << "testing divide by 0" << endl; 
  try { 
    x = 0.0; 
    y = 1.0; 
    z = y / x; 
    cerr << "z is " << z << endl; 
  } 
  catch (exception e) { 
    cerr << "caught exception " << e.what() << endl; 
  } 
  catch(...) { 
    cerr << "caught ... exception" << endl; 
  } 
  return EXIT_SUCCESS; 
} 

The resulting output is as follows:


tagged 1062% a.out               
testing divide by 0 
caught ... exception 

8.8 C++ Exceptions and Threads [Tru64]

C++ exceptions are thread safe. This means that multiple threads within a process can throw and catch exceptions concurrently. However, exceptions do not propagate from one thread to another, nor can one thread catch an exception thrown by another thread.

Because C++ exceptions are implemented using the exception handling facilities described in the HP Tru64 UNIX Calling Standard for Alpha System, C++ modules do work properly when they are part of a program that makes other uses of the same exception handling facilities.

The raising and handling of DECthreads exceptions can result in the destruction of C++ automatic objects. If the handling of a DECthreads exception results in an unwind through a C++ function's stack frame, then destructors are called for automatic objects declared in that stack frame, just as though a C++ exception had been caught by a handler in an outer stack frame.

The C++ exception handling facility can also be used to catch DECthreads exceptions that are raised independently of C++ throw expressions. A C++ catch( .. . ) handler catches both C++ thrown exceptions and DECthreads exceptions.

However, C++ exception mechanisms ( try , catch , throw ) cannot be used within the same function as DECthreads exception mechanisms ( TRY , CATCH , RAISE , and so forth). Because both exception mechanisms attempt to establish their own specific handlers, the results will be undefined.

The set_terminate() and set_unexpected() functions set the terminate() and unexpected() handlers for the calling thread. Therefore, each thread in a program has its own terminate() and unexpected() handlers.

If you want every thread in your program to use the same nondefault terminate() or unexpected() handlers, you must call the set_terminate() and set_unexpected() functions separately from each thread.

For more information about threads and DECthreads exceptions, see the Guide to DECthreads manual.

Note that the advantage of using C++ exceptions is that entering the try block is much faster than entering a pthread try block.

The advantage of using pthread exceptions is that you can call pthread_exc_report_np(THIS_CATCH) to give more information about the exception caught, as shown in the following example.


#include <pthread.h> 
#include <pthread_exception.h> 
#include <stdio.h> 
 
struct C { 
 int i; 
 static int count; 
 C() : i(count++) { printf("ctor %d\n", i); } 
 ~C() { printf("dtor %d\n", i); } 
}; 
 
int C::count =0; 
 
int foo(int i, int j, int *p) { 
    int k = j / i; 
    *p = 25; /* illegal mem access */ 
    return k; 
} 
 
// C++ version. 
void * theThread_cxx(void * arg) 
{ 
  int i = 0, j = 10, k, *p; 
 
  printf("Enter thread\n"); 
  sleep(2); 
 
  try { 
    k = foo(i,j,p); 
 
  } catch (...) { 
      printf("Caught some exception...\n"); 
      // pthread_exc_report_np(THIS_CATCH); 
  } 
 
  printf("exit thread\n"); 
  return(0); 
} 
 
// Threads version. 
void * theThread(void * arg) 
{ 
  C d; 
  int i = 0, j = 10, k, *p; 
 
  printf("Enter thread\n"); 
  sleep(2); 
 
  TRY 
    k = foo(i,j,p); 
 
   CATCH_ALL 
      printf("Caught some exception...\n"); 
      pthread_exc_report_np(THIS_CATCH); 
      throw 5; 
   ENDTRY 
 
    printf("exit thread\n"); 
  return(0); 
} 
 
void * theThread_wrapper(void * arg) 
{ 
  try { 
    theThread(arg); 
  } catch (int) { 
    printf("caught an int\n"); 
  } 
  return 0; 
} 
    
int main() 
{ 
  pthread_t thread; 
  pthread_attr_t attr; 
  int status = 0; 
  register int i; 
 
  printf("begin main\n"); 
  pthread_attr_init(&attr); 
 
  // Make 3 copies of the pthread exception handling thread. 
  for(i=0; i<3; i++) { 
      status = pthread_create(&thread, &attr, theThread_wrapper, 0); 
      if(status) 
        { 
          printf("***ERROR***, pthread_create failed\n"); 
        } 
      pthread_join(thread, 0); 
    } 
 
  // Make the C++ exception handling thread. 
  status = pthread_create(&thread, &attr, theThread_cxx, 0); 
  if(status) 
        { 
          printf("***ERROR***, pthread_create failed\n"); 
        } 
  pthread_join(thread, 0); 
  printf("end main\n"); 
 
  return(0); 
} 


Previous Next Contents Index
About PDF files: The PDF files on this site can be read online or printed using Adobe® Acrobat® Reader. If you do not have this software on your system, you may download it from Adobe's website.
Privacy statement Using this site means you accept its terms C++ support
© 2008 Hewlett-Packard Development Company, L.P.