|
|
HP C++
|
Previous | Contents | Index |
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.
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.
HP C++ optimizes the implementation of exception handling for normal execution, as follows:
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.
Some recommendations for optimal results when using exception handling in HP C++ are:
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.
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.
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.
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 |
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 |
|