exception handling1

29
Exception Handlers One exception handler for every type of exception that we want to catch. 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 }

Upload: guest739536

Post on 20-May-2015

1.061 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Exception Handling1

Exception HandlersOne exception handler for every type of exception that we want to catch.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

}

Page 2: Exception Handling1

Exception HandlersEach catch clause takes a single argument of one particular type.The identifier id1,id2 may be used inside the handler.The identifier is not necessary.Handlers must appear directly after try block with no other code in between.Handler searched like the switch statement except for the break keyword.

Page 3: Exception Handling1

Exception Specification

Informs the user of a function about the type of exceptions the function can throw.

Is a part of function declaration appearing after the argument list of the function.

Uses keyword throw followed by parenthesized list of all potential exception types.

Page 4: Exception Handling1

Exception specification contd.void f() throw(toobig, toosmall, divzero);Function can throw exceptions of type toobig, toosmall, divzero only.void f();Any type of exception may be thrown from the function.void f() throw();No exceptions are thrown from a function.

Page 5: Exception Handling1

unexpected()Called when you throw something other than what appears in the exception specification.Implemented with a pointer to a function.By default, unexpected calls terminate.We can change its behavior using the set_unexpected() function which takes the address of a function with no arguments and void return value.Returns previous value of the unexpected( ) pointer which can be restored later.Header file <exception>

Page 6: Exception Handling1

set_unexpected() e.gvoid my_unexpected(){

cout << "unexpected exception thrown";

exit(1);

}

int main() {//set our function handler for unexpected exceptions

set_unexpected(my_unexpected);//code that raises an unexpected exception

}

Page 7: Exception Handling1

Uncaught exceptions

If none of the exception handlers following a particular try block matches an exception,then

Exception moves to the next-higher context, i.e. the function/try block surrounding the try block that failed to catch the exception.

This process continues until, at some level, a handler matches the exception.

At that point, the exception is considered “caught” and no further searching occurs.

Page 8: Exception Handling1

terminate( )

terminate() is automatically called if an exception is uncaught.

Is actually a pointer to a function.

Default value is the Standard C library function abort( ).

No cleanups occur for an uncaught exception

Page 9: Exception Handling1

set_terminate( )We can install our own terminate() function using the set_terminate() function.Returns a pointer to the previous terminate() function.Custom terminate() takes no arguments and returns a void value.Any terminate( ) handler installed must not return or throw an exception, but instead must call some sort of program-termination function.

Page 10: Exception Handling1

set_terminate( ) e.g.

void terminator() {

cout << “Custom terimate ftn" << endl;

abort();

}

void (*old_terminate)()

= set_terminate(terminator);

Page 11: Exception Handling1

set_terminate( ) e.g.#include <eh.h>#include <process.h>#include <iostream.h>

void term_func(){ cout << "term_func() was called by terminate().\n"; // ... cleanup tasks performed here // If this function does not exit, abort is called. exit(-1);}void main(){ int i = 10, j = 0, result; set_terminate( term_func ); try{ if( j == 0 ) throw "Divide by zero!"; else result = i/j; } catch( int ){ cout << "Caught some integer exception.\n"; } cout << "This should never print.\n";}

Page 12: Exception Handling1

Catching any ExceptionIf a function has no exception specification, any type of exception can be thrown.Solution is to create a handler that catches any exception.Done by using ellipses in the argument list.catch(...) {cout << “An exception was thrown" << endl;}Should be put at the end of exception handlers.

Page 13: Exception Handling1

Rethrowing an exceptionSometimes we would want to rethrow the exception that was just caught.Particularly when we use the ellipses to catch any exception because there is no information available about the exception.Accomplished by saying throw with no argument.catch(...) {

cout << "an exception was thrown" << endl;

throw;}Further catch clauses for the same try block are still ignored

Page 14: Exception Handling1

Cleaning Up

All objects in that scope whose constructors have been completed will have destructors called.

If an exception is thrown before a constructor is completed, the associated destructor will not be called for that object.

Page 15: Exception Handling1

Cleaning Up (e.g)class Cat {

public:Cat() { cout << "Cat()" << endl; }~Cat() { cout << "~Cat()" << endl; }

};class Dog {

public:void* operator new(size_t sz) {

cout << "allocating a Dog" << endl;throw int(47);

}void operator delete(void* p) {

cout << "deallocating a Dog" << endl;::delete p;

}};

Page 16: Exception Handling1

Cleaning Up (e.g) contd.class UseResources {

Cat* bp;Dog* op;

public:UseResources(int count = 1) {

cout << "UseResources()" << endl;bp = new Cat[count];op = new Dog;

}~UseResources() {

cout << "~UseResources()" << endl;delete []bp; // Array deletedelete op;

}};

Page 17: Exception Handling1

Cleaning Up (e.g) contd.int main() {

try {UseResources ur(3);

} catch(int) {cout << "inside handler" << endl;}

}

The output is the followingUseResources()Cat()Cat()Cat()allocating a Doginside handler

Page 18: Exception Handling1

Solution

Is to place allocations inside their own objects with their own constructors and destructors.

Each allocation becomes atomic.

If it fails, the other resource allocation objects are properly cleaned up.

Templates offer a solution.

Page 19: Exception Handling1

Solution using templatestemplate<class T, int sz = 1> class PWrap {

T* ptr;public:

PWrap() {ptr = new T[sz];cout << "PWrap constructor" << endl;

}~PWrap() {

delete []ptr;cout << "PWrap destructor" << endl;

}T& operator[](int i){

if(i >= 0 && i < sz) return ptr[i]; }};

Page 20: Exception Handling1

Solution using templates contd.class Cat {

public:Cat() { cout << "Cat()" << endl; }~Cat() { cout << "~Cat()" << endl; }void g() {}

};class Dog {

public:void* operator new[](size_t sz) {cout << "allocating an Dog" << endl;throw int(47);}void operator delete[](void* p) {cout << "deallocating an Dog" << endl;::delete p;}

};

Page 21: Exception Handling1

Solution using templates contd.class UseResources {

PWrap<Cat, 3> Bonk;PWrap<Dog> Og;

public:UseResources() : Bonk(), Og() {

cout << "UseResources()" << endl;}~UseResources() {

cout << "~UseResources()" << endl;}void f() { Bonk[1].g(); }

};

Page 22: Exception Handling1

Solution using templates contd.int main() {try {

UseResources ur;}catch(int) {

cout << "inside handler" << endl;}catch(...) {

cout << "inside catch(...)" << endl;}

}

Page 23: Exception Handling1

Solution using templates contd.Cat()Cat()Cat()PWrap constructorallocating a Dog~Cat()~Cat()~Cat()PWrap destructorinside handler

Page 24: Exception Handling1

Exception MatchingException-handling system looks through the “nearest” handlers in the order they are written.When it finds a match, the exception is considered handled, and no further searching occurs.Matching an exception doesn’t require a perfect match between the exception and its handler.An object or reference to a derived-class object will match a handler for the base class.If handler is for an object rather than a reference, the exception object is “sliced” as it is passed to the handler.

Page 25: Exception Handling1

Exception Matchingclass X {

public:class Trouble {};class Small : public Trouble {};class Big : public Trouble {};void f() { throw Big(); }

};

Page 26: Exception Handling1

Exception Matchingint main() {

X x;try {

x.f();} catch(X::Trouble) {

cout << "caught Trouble" << endl;} catch(X::Small) { // Hidden by previous handler:

cout << "caught Small Trouble" << endl;} catch(X::Big) {

cout << "caught Big Trouble" << endl;}

}

Page 27: Exception Handling1

Catch by reference not by value

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.

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.

Page 28: Exception Handling1

Catch by reference not by valueclass Base {

public:virtual void what() {

cout << "Base" << endl;}

};class Derived : public Base {

public:void what() {

cout << "Derived" << endl;}

};void f() { throw Derived(); }

Page 29: Exception Handling1

Catch by reference not by valueint main() {

try {f();

} catch(Base b) {b.what();

}try {

f();} catch(Base& b) {b.what();}

}

The output isBaseDerived