1 / 113

Topics on Exceptions & Assertions

Topics on Exceptions & Assertions. Asyncronous Exceptions Using assert.h and signal.h User Defined Exceptions C++ Exceptions Throwing Exceptions Try Blocks Handlers Exception Specification terminate() and unexpected() The Philosophy Of Error Recovery. Error Recovery. Exceptions.

colm
Télécharger la présentation

Topics on Exceptions & Assertions

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Topics on Exceptions & Assertions • Asyncronous Exceptions • Using assert.h and signal.h • User Defined Exceptions • C++ Exceptions • Throwing Exceptions • Try Blocks • Handlers • Exception Specification • terminate() and unexpected() • The Philosophy Of Error Recovery

  2. Error Recovery

  3. Exceptions • Exceptions generally are unexpected error conditions • floating point divide by zero • out of memory • Normally these conditions terminate the user program with a system-provided error message • C++ gives the programmer the opportunity to recover from these conditions and continue program execution

  4. Can’t we just assume that the functions we write will work will all the data we get? No, we need to put in some assertions. Program Correctness

  5. Program Correctness and Assertions • Program correctness: computation terminated with correct output dependent on correct input • Invoker of computation had the responsibility of providing correct input as a precondition • Successful computation satisfied postcondition • Intention of providing a fully formal proof of correctness is an idealization not usually done

  6. Programmer Discipline and Assertions • The discipline of thinking out appropriate assertions frequently causes the programmer to avoid bugs and pitfalls • Assertions can be monitored at run-time to provide very useful diagnostics • The C and C++ communities increasingly emphasize the use of assertions

  7. The assert Macro • The standard library assert.h provides the macro • void assert(int expression); • If the expression evaluates as false, then execution is aborted with diagnostic output • The assertions are discarded if the macro NDEBUG is defined

  8. Preconditions and Postconditions • Precondition • assert (grade > = 0); • student.score = grade; • Postcondition • minmax (data, size, min, max); • assert (min <= max);

  9. Assertions and Contracts • Assertions provide guarantees the code will work correctly • The client or user of code guarantees that the inputs to the code are correct • The manufacturer or provider of code guarantees that the outputs from the code are correct

  10. vect Without the assert Macro • vect::vect(int n) • { • if (n <= 0) { • cerr << "illegal vect size " << n << endl; • exit(1); • } • size = n; • p = new int[size]; //assert (p != 0); • }

  11. vect With the assert Macro • vect::vect(int n) • { • assert (n > 0); //contractual precondition • size = n; • p = new int[size]; • assert (p != 0); //contractual postcondition • } • Assertions replace ad hoc use of conditional tests with a more uniform methodology • This is conducive to better practice • The down side is that the assertion methodology does not allow a retry or other repair strategy to continue program execution

  12. Sophisticated Approach using checks.h • Different testing levels may be used, as found in the Borland checks.h file flag _DEBUG Testing Level _DEBUG 0 no testing _DEBUG 1 PRECONDITION tests only _DEBUG 2 CHECK tests also

  13. Using Testing Levels • Once the library functions are thought to be correct, the level of checking is reduced to only testing preconditions • Once the client code is debugged, all testing can be suspended

  14. Placing Assertions in Bubble Sort (1 of 3) • Bubble sort does not work correctly • Place assertions in this code to test that the code is working properly • // Title: bubble • #include <iostream.h> • void swap(int a, int b) • { • int temp = a; • a = b; • b = temp; • }

  15. Placing Assertions in Bubble Sort (2 of 3) • void bubble(int a[], int size) • { • int i, j; • for (i = 0; i != size; ++i) • for (j = i ; j != size; ++j) • if (a[j] < a [j + 1]) • swap (a[j], a[j + 1]); • };

  16. Placing Assertions in Bubble Sort (3 of 3) • main() • { • int t[10] = { 9, 4, 6, 4, 5, 9, —3, 1, 0, 12}; • bubble(t, 10); • for (int i = 0; i < 10; ++i) • cout << t[i] << '\t'; • cout << "\nsorted? " << endl; • }

  17. Assertions to Detect Failure • Postcondition that will fail in general • c = a - b; • swap (a, b); • assert (-c == (a - b) );

  18. I put in an assertion to make sure that the swap function does what I intended. Assertions in Bubble Sorting • if (a[j] < a[j + 1] { • swap (a[j], a[j + 1]); • assert (a[j] >= a[j + 1]); • }

  19. Assertions in main() • for (int i = 0; i < 10; ++i) { • cout << t[i] << '\t'; • assert (i == 9 || t[i] >= t[i + 1]); • // short circuit t[9] > t[10] not evaluated • }

  20. Assertions and Classes • Member functions are guaranteed to work on correct data and input • If a client owns a stack s, then push works if stack is not full and if input is correct • Precondition guaranteed by client • s.full() is false • data is legal • Postcondition guaranteed by manufacturer • s.top is data

  21. The signal.h Functions • The ANSI C package signal.h handles asynchronous hardware exceptions • These exceptions are system-dependent and usually are raised by hardware detection of a special condition • The signal.h file also handles synchronous exceptions using the raise() function • While not as sophisticated as C++ language exception handling, signal.h has a long history as a useful library

  22. System-defined Exceptions & signal.h • The signal.h file provides a standard mechanism for handling system-defined exceptions in a straightforward manner • Exceptions are defined within this library and are system-dependent integer values • #define SIGINT 2 /*interrupt signal */ • #define SIGFPE 8 /*floating point exception */ • #define SIGABRT 22 /*abort signal */ • The system can raise these exceptions

  23. Raising Exceptions • Hitting control-C on the keyboard, on many systems, generates an interrupt, usually killing the current user process • The raise() function, prototyped in signal.h, can be used to generate an explicit exception • //floating point exception signal raised • raise(SIGFPE);

  24. Let’s change the way the system handles floating point errors. Overriding the System Error Handling

  25. Installing the Handler using signal • Exceptions can be handled by use of the signal() function • It associates a handler function with a signal • It can be used to ignore the signal or to reinstall the default action • Invoking signal() is called installing the handler and it replaces the normal system action with the user-defined handler

  26. Using signal • Call my_abrt() if SIGABRT is raised • signal(SIGABRT, my_abort); • Default action if SIGABRT is raised • signal(SIGABRT, SIG_DFL); • Ignore SIGFPE • signal(SIGFPE, SIG_IGN);

  27. Keyboard Termination (1 of 4) • A loop interrupted from the keyboard • Upon interruption, the handler requests from the user whether or not the program should continue executing • // Title: interrupt • //Interrupts handled using signal.h • #include <signal.h> • #include <time.h> • #include <iostream.h> • #include <stdlib.h> • #define CPS CLOCKS_PER_SEC

  28. Requiring Keyboard Input The screen saver program only terminates when you hit a key

  29. Keyboard Termination (2 of 4) • void cntrl_c_handler(int sig); • main() • { • int i = 0, j; • cout << "COUNT TO J MILLION, Enter j:"; • cin >> j; • j *= 1000000; • signal(SIGINT, cntrl_c_handler); • cout << (double)clock()/CPS << " start time\n";

  30. Keyboard Termination (3 of 4) • while (1) { • ++i; • if (i > j) { • cout <<(double)clock()/CPS << " end loop\n"; • cout << " HIT " << j/1000000 << " MILLION" • << endl; • raise(SIGINT); • cout << "\nEnter j: "; • cin >> j; • j *= 1000000; i = 0; • cout << (double)clock()/CPS << " start loop\n"; • } • } • }

  31. Keyboard Termination (4 of 4) • void cntrl_c_handler(int sig) • { • char c; • cout << "INTERRUPT"; • cout << "\ntype y to continue: "; • cin >> c; • if (c == 'y') • signal(SIGINT, cntrl_c_handler); • else • exit(0); • }

  32. Comments on handler Program (1 of 2) • The handler cntrl_c_handler function is associated with the interrupt SIGINT • On detecting the next interrupt, system invokes cntrl_c_handler() instead of default action • The function clock() is found in time.h and it reads out elapsed cpu cycles in local units • Divided by the integer constant CPS, it gives times in seconds for executing the computation • Interrupt signal raised by explicit raise(SIGINT) • Implicitly cntrl_c_handler() is invoked

  33. Comments on handler Program (2 of 2) • User-defined cntrl_c_handler handles a SIGINT exception is invoked when on interrupt to ask the user whether the program is to be continued • On the request to continue execution, the exception handler is reinstalled • Without the handler being reinstalled, system reverts to its default handling of the interrupt • exit() function in stdlib.h is invoked to terminate execution if the user selects not to continue

  34. A Modified Handler • void cntrl_c_handler(int sig) • { • char c; • static int count = 0; • cout << "INTERRUPT"; • cout << "\ntype y to continue:"; • cin >> c; • if (c == 'y' && count++ < N) • signal(SIGINT, cntrl_c_handler); • else • abort(); • } • The variable N is an integer constant

  35. The setjmp.h Function (1 of 2) • On ANSI systems the file setjmp.h provides declarations that allow nonlocal resumption of processing • typedef long jmp_buf[16]; • space to holdenvironment • int setjmp(jmp_buf env); • save callingenvironment • void longjmp(jmp_buf env, int v); • restoreenvironment

  36. The setjmp.h Function (2 of 2) • We could rewrite the code in the interrupt program to return to the beginning of the timing loop anytime an interrupt is caught • Using setjmp.h bypasses a normal block exit and can be dangerous because objects can be left undestroyed

  37. If the size of the vect is negative or 0, or it there isn’t enough memory, I’ll raise an exception Exceptions and vect

  38. Handling vect Exceptions (1 of 3) • const int SIGHEAP = SIGUSR1; • const int SIGSIZE = SIGUSR2; • vect::vect(int n) • { • if (n <= 0) { • raise(SIGSIZE); • cout << "\nEnter vect size n: "; • cin >> n; //retry with user provided value • } • p = new int[n]; • if (p == 0) { • raise(SIGHEAP); • p = new int[n]; • } • }

  39. Handling vect Exceptions (2 of 3) • void vect_size_handler(int sig) • { • char c; • cout << "\nSIZE ERROR\nENTER y to continue" • << " with default: "; • cin >> c; • if (c == 'y') { • signal(SIGSIZE, vect_size_handler); • } • else • exit(0); • }

  40. Handling vect Exceptions (3 of 3) • void vect_heap_handler(int sig) • { • //Possible action to reclaim store for heap • //or exit gracefully • . . . • }

  41. Replacing Assertions with Handlers • Replace the assertions with conditions that raise user-defined signals then define handlers that can provide appropriate action • Contrast this complicated technique with the standard technique for handling heap exhaustion using the set_new_handler()

  42. C++ Exceptions • C++ introduces an exception handling mechanism that is sensitive to context • It can be more informed than a signal.h handler and can provide more sophisticated recovery • It is not intended to handle the asynchronous exceptions defined in signal.h

  43. C++ Exceptions with try, catch, throw • try { //try block • . . . • a[i] = a[j] = a[k]; • . . . //relevant handlers follow • } • catch (int index) { ... } • catch (char* message) { ... } • int& vect::operator[](int i) • { • if (i < 0 || i >= size) • throw (i); //throwing an exception • else • return (p[i]); • }

  44. The try Block • Context for raising an exception is a try block • Handlers are declared at the end of a try block using the keyword catch • C++ code is allowed to directly raise an exception in a try block by using the throw expression • Exception is handled by invoking appropriate handler selected from a list of handlers found immediately after handler's try block

  45. Modifying vect for try and throw (1 of 2) • vect::vect(int n) • { • if (n < 1) • throw (n); • p = new int[n]; • if (p == 0) • throw ("FREE STORE EXHAUSTED"); • }

  46. Modifying vect for try and throw (2 of 2) • void g() • { • try { • vect a(n), b(n); • . . . • } • catch (int n) { . . .} //catch incorrect size • catch (char* error) { . . .} //catch no-memory • }

  47. Comments on the vect Exception Handling • The first throw() has an integer argument and matches the catch(int n) signature • When an incorrect array size has been passed as an argument to the constructor, this handler is expected to perform an appropriate action, for example, an error message and abort • The second throw() has a pointer to character argument and matches the catch(char* error) signature

  48. Throwing Exceptions

  49. Throwing Exceptions (1 of 2) • Syntactically throw expressions come in two forms • throw • throw expression • The throw expression raises an exception • The innermost try block in which an exception is raised is used to select the catch statement that processes the exception

  50. Throwing Exceptions (2 of 2) • The throw expression with no argument rethrows the current exception and is typically used when a second handler called from the first handler is needed to further process the exception • Expression thrown is a static, temporary object that persists until exception handling is exited • The expression is caught by a handler that may use this value

More Related