Exception Handling1


Published on

Published in: Technology, Business
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Exception Handling1

  1. 1. Exception Handlers <ul><li>One exception handler for every type of exception that we want to catch. </li></ul><ul><li>Exception handlers immediately follow the try block & are denoted by the keyword catch, e.g. try { // code that may generate exceptions } catch(type1 id1) { // handle exceptions of type1 } catch(type2 id2) { // handle exceptions of type2 } </li></ul>
  2. 2. Exception Handlers <ul><li>Each catch clause takes a single argument of one particular type. </li></ul><ul><li>The identifier id1,id2 may be used inside the handler. </li></ul><ul><li>The identifier is not necessary. </li></ul><ul><li>Handlers must appear directly after try block with no other code in between . </li></ul><ul><li>Handler searched like the switch statement except for the break keyword. </li></ul>
  3. 3. Exception Specification <ul><li>Informs the user of a function about the type of exceptions the function can throw. </li></ul><ul><li>Is a part of function declaration appearing after the argument list of the function. </li></ul><ul><li>Uses keyword throw followed by parenthesized list of all potential exception types. </li></ul>
  4. 4. Exception specification contd. <ul><li>void f() throw(toobig, toosmall, divzero); </li></ul><ul><li>Function can throw exceptions of type toobig, toosmall, divzero only. </li></ul><ul><li>void f(); </li></ul><ul><li>Any type of exception may be thrown from the function. </li></ul><ul><li>void f() throw(); </li></ul><ul><li>No exceptions are thrown from a function. </li></ul>
  5. 5. unexpected() <ul><li>Called when you throw something other than what appears in the exception specification. </li></ul><ul><li>Implemented with a pointer to a function. </li></ul><ul><li>By default, unexpected calls terminate . </li></ul><ul><li>We can change its behavior using the set_unexpected() function which takes the address of a function with no arguments and void return value. </li></ul><ul><li>Returns previous value of the unexpected( ) pointer which can be restored later. </li></ul><ul><li>Header file <exception> </li></ul>
  6. 6. set_unexpected() e.g <ul><li>void my_unexpected(){ </li></ul><ul><li>cout << &quot;unexpected exception thrown&quot;; </li></ul><ul><li>exit(1); </li></ul><ul><li>} </li></ul><ul><li>int main() { </li></ul><ul><li>//set our function handler for unexpected exceptions </li></ul><ul><li>set_unexpected(my_unexpected); </li></ul><ul><li>//code that raises an unexpected exception </li></ul><ul><li>} </li></ul>
  7. 7. Uncaught exceptions <ul><li>If none of the exception handlers following a particular try block matches an exception,then </li></ul><ul><ul><li>Exception moves to the next-higher context, i.e. the function/ try block surrounding the try block that failed to catch the exception. </li></ul></ul><ul><li>This process continues until, at some level, a handler matches the exception. </li></ul><ul><li>At that point, the exception is considered “caught” and no further searching occurs. </li></ul>
  8. 8. terminate( ) <ul><li>terminate() is automatically called if an exception is uncaught. </li></ul><ul><li>Is actually a pointer to a function. </li></ul><ul><li>Default value is the Standard C library function abort( ) . </li></ul><ul><li>No cleanups occur for an uncaught exception </li></ul>
  9. 9. set_terminate( ) <ul><li>We can install our own terminate() function using the set_terminate() function. </li></ul><ul><li>Returns a pointer to the previous terminate() function. </li></ul><ul><li>Custom terminate() takes no arguments and returns a void value. </li></ul><ul><li>Any terminate( ) handler installed must not return or throw an exception, but instead must call some sort of program-termination function. </li></ul>
  10. 10. set_terminate( ) e.g. <ul><li>void terminator() { </li></ul><ul><li>cout << “Custom terimate ftn&quot; << endl; </li></ul><ul><li>abort(); </li></ul><ul><li>} </li></ul><ul><li>void (*old_terminate)() </li></ul><ul><li>= set_terminate(terminator); </li></ul>
  11. 11. set_terminate( ) e.g. <ul><li>#include <eh.h> </li></ul><ul><li>#include <process.h> </li></ul><ul><li>#include <iostream.h> </li></ul><ul><li>void term_func(){ </li></ul><ul><li>cout << &quot;term_func() was called by terminate(). &quot;; </li></ul><ul><li>// ... cleanup tasks performed here </li></ul><ul><li>// If this function does not exit, abort is called. </li></ul><ul><li>exit(-1); </li></ul><ul><li>} </li></ul><ul><li>void main(){ </li></ul><ul><li>int i = 10, j = 0, result; </li></ul><ul><li>set_terminate( term_func ); </li></ul><ul><li>try{ </li></ul><ul><li>if( j == 0 ) throw &quot;Divide by zero!&quot;; </li></ul><ul><li>else result = i/j; </li></ul><ul><li>} </li></ul><ul><li>catch( int ){ </li></ul><ul><li>cout << &quot;Caught some integer exception. &quot;; </li></ul><ul><li>} </li></ul><ul><li>cout << &quot;This should never print. &quot;; </li></ul><ul><li>} </li></ul>
  12. 12. Catching any Exception <ul><li>If a function has no exception specification, any type of exception can be thrown. </li></ul><ul><li>Solution is to create a handler that catches any exception. </li></ul><ul><li>Done by using ellipses in the argument list. </li></ul><ul><li>catch(...) { </li></ul><ul><li>cout << “An exception was thrown&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>Should be put at the end of exception handlers. </li></ul>
  13. 13. Rethrowing an exception <ul><li>Sometimes we would want to rethrow the exception that was just caught. </li></ul><ul><li>Particularly when we use the ellipses to catch any exception because there is no information available about the exception. </li></ul><ul><li>Accomplished by saying throw with no argument. </li></ul><ul><li>catch(...) { </li></ul><ul><li>cout << &quot;an exception was thrown&quot; << endl; </li></ul><ul><li>throw; </li></ul><ul><li>} </li></ul><ul><li>Further catch clauses for the same try block are still ignored </li></ul>
  14. 14. Cleaning Up <ul><li>All objects in that scope whose constructors have been completed will have destructors called. </li></ul><ul><li>If an exception is thrown before a constructor is completed, the associated destructor will not be called for that object. </li></ul>
  15. 15. Cleaning Up (e.g) <ul><li>class Cat { </li></ul><ul><li>public: </li></ul><ul><li>Cat() { cout << &quot;Cat()&quot; << endl; } </li></ul><ul><li>~Cat() { cout << &quot;~Cat()&quot; << endl; } </li></ul><ul><li>}; </li></ul><ul><li>class Dog { </li></ul><ul><li>public: </li></ul><ul><li>void* operator new(size_t sz) { </li></ul><ul><li>cout << &quot;allocating a Dog&quot; << endl; </li></ul><ul><li>throw int(47); </li></ul><ul><li>} </li></ul><ul><li>void operator delete(void* p) { </li></ul><ul><li>cout << &quot;deallocating a Dog&quot; << endl; </li></ul><ul><li>::delete p; </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  16. 16. Cleaning Up (e.g) contd. <ul><li>class UseResources { </li></ul><ul><li>Cat* bp; </li></ul><ul><li>Dog* op; </li></ul><ul><li>public: </li></ul><ul><li>UseResources(int count = 1) { cout << &quot;UseResources()&quot; << endl; </li></ul><ul><li>bp = new Cat[count]; </li></ul><ul><li>op = new Dog; } </li></ul><ul><li>~UseResources() { cout << &quot;~UseResources()&quot; << endl; </li></ul><ul><li>delete []bp; // Array delete </li></ul><ul><li>delete op; } </li></ul><ul><li>}; </li></ul>
  17. 17. Cleaning Up (e.g) contd. <ul><li>int main() { </li></ul><ul><li>try { </li></ul><ul><li>UseResources ur(3); </li></ul><ul><li>} catch(int) { </li></ul><ul><li>cout << &quot;inside handler&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>The output is the following </li></ul><ul><li>UseResources() </li></ul><ul><li>Cat() </li></ul><ul><li>Cat() </li></ul><ul><li>Cat() </li></ul><ul><li>allocating a Dog </li></ul><ul><li>inside handler </li></ul>
  18. 18. Solution <ul><li>Is to place allocations inside their own objects with their own constructors and destructors. </li></ul><ul><li>Each allocation becomes atomic. </li></ul><ul><li>If it fails, the other resource allocation objects are properly cleaned up. </li></ul><ul><li>Templates offer a solution. </li></ul>
  19. 19. Solution using templates <ul><li>template<class T, int sz = 1> class PWrap { </li></ul><ul><li>T* ptr; </li></ul><ul><li>public: </li></ul><ul><li>PWrap() { </li></ul><ul><li>ptr = new T[sz]; </li></ul><ul><li>cout << &quot;PWrap constructor&quot; << endl; } </li></ul><ul><li>~PWrap() { </li></ul><ul><li>delete []ptr; </li></ul><ul><li>cout << &quot;PWrap destructor&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>T& operator[](int i){ </li></ul><ul><li>if(i >= 0 && i < sz) return ptr[i]; } }; </li></ul>
  20. 20. Solution using templates contd. <ul><li>class Cat { </li></ul><ul><li>public: </li></ul><ul><li>Cat() { cout << &quot;Cat()&quot; << endl; } </li></ul><ul><li>~Cat() { cout << &quot;~Cat()&quot; << endl; } </li></ul><ul><li>void g() {} </li></ul><ul><li>}; </li></ul><ul><li>class Dog { </li></ul><ul><li>public: </li></ul><ul><li>void* operator new[](size_t sz) { </li></ul><ul><li>cout << &quot;allocating an Dog&quot; << endl; </li></ul><ul><li>throw int(47); </li></ul><ul><li>} </li></ul><ul><li>void operator delete[](void* p) { </li></ul><ul><li>cout << &quot;deallocating an Dog&quot; << endl; </li></ul><ul><li>::delete p; </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  21. 21. Solution using templates contd. <ul><li>class UseResources { </li></ul><ul><li>PWrap<Cat, 3> Bonk; </li></ul><ul><li>PWrap<Dog> Og; </li></ul><ul><li>public: </li></ul><ul><li>UseResources() : Bonk(), Og() { </li></ul><ul><li>cout << &quot;UseResources()&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>~UseResources() { </li></ul><ul><li>cout << &quot;~UseResources()&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>void f() { Bonk[1].g(); } </li></ul><ul><li>}; </li></ul>
  22. 22. Solution using templates contd. <ul><li>int main() { </li></ul><ul><li>try { </li></ul><ul><li>UseResources ur; </li></ul><ul><li>} </li></ul><ul><li>catch(int) { </li></ul><ul><li>cout << &quot;inside handler&quot; << endl; </li></ul><ul><li>}catch(...) { </li></ul><ul><li>cout << &quot;inside catch(...)&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  23. 23. Solution using templates contd. <ul><li>Cat() </li></ul><ul><li>Cat() </li></ul><ul><li>Cat() </li></ul><ul><li>PWrap constructor </li></ul><ul><li>allocating a Dog </li></ul><ul><li>~Cat() </li></ul><ul><li>~Cat() </li></ul><ul><li>~Cat() </li></ul><ul><li>PWrap destructor </li></ul><ul><li>inside handler </li></ul>
  24. 24. Exception Matching <ul><li>Exception-handling system looks through the “nearest” handlers in the order they are written. </li></ul><ul><li>When it finds a match, the exception is considered handled, and no further searching occurs. </li></ul><ul><li>Matching an exception doesn’t require a perfect match between the exception and its handler. </li></ul><ul><li>An object or reference to a derived-class object will match a handler for the base class. </li></ul><ul><li>If handler is for an object rather than a reference, the exception object is “sliced” as it is passed to the handler. </li></ul>
  25. 25. Exception Matching <ul><li>class X { </li></ul><ul><li>public: </li></ul><ul><li>class Trouble {}; </li></ul><ul><li>class Small : public Trouble {}; </li></ul><ul><li>class Big : public Trouble {}; </li></ul><ul><li>void f() { throw Big(); } </li></ul><ul><li>}; </li></ul>
  26. 26. Exception Matching <ul><li>int main() { </li></ul><ul><li>X x; </li></ul><ul><li>try { </li></ul><ul><li>x.f(); </li></ul><ul><li>} </li></ul><ul><li>catch(X::Trouble) { </li></ul><ul><li>cout << &quot;caught Trouble&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>catch(X::Small) { // Hidden by previous handler: </li></ul><ul><li>cout << &quot;caught Small Trouble&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>catch(X::Big) { </li></ul><ul><li>cout << &quot;caught Big Trouble&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  27. 27. Catch by reference not by value <ul><li>If you throw an object of a derived class and it is caught by value in a handler for an object of the base class, that object is “sliced” – that is, the derived-class elements are cut off and you’ll end up with the base-class object being passed. </li></ul><ul><li>Chances are this is not what you want because the object will behave like a base-class object and not the derived class object it really is. </li></ul>
  28. 28. Catch by reference not by value <ul><li>class Base { </li></ul><ul><li>public: </li></ul><ul><li>virtual void what() { </li></ul><ul><li>cout << &quot;Base&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>class Derived : public Base { </li></ul><ul><li>public: </li></ul><ul><li>void what() { </li></ul><ul><li>cout << &quot;Derived&quot; << endl; </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>void f() { throw Derived(); } </li></ul>
  29. 29. Catch by reference not by value <ul><li>int main() { </li></ul><ul><li>try { </li></ul><ul><li>f(); </li></ul><ul><li>} catch(Base b) { </li></ul><ul><li>b.what(); </li></ul><ul><li>} </li></ul><ul><li>try { </li></ul><ul><li>f(); </li></ul><ul><li>} catch(Base& b) { </li></ul><ul><li>b.what(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>The output is Base Derived