cpsc 252 exception handling page 1 exceptions and exception handling client programmers can make...
TRANSCRIPT
CPSC 252 Exception Handling Page 1
Exceptions and exception handling
Client programmers can make errors using a class
• attempting to dequeue an item from an empty queue
• even though we have placed a precondition on the method
Item_type Queue::dequeue( void )
// Pre: Queue is not empty
• the client might not check before calling the dequeue()
What should the dequeue() member function do?
More generally, what should any function do when an error arises?
CPSC 252 Exception Handling Page 2
Possible ways to handle errors
• Do nothing and run the risk of severe problems such as a segmentation fault resulting in abnormal program termination
• Check for the error (the failing precondition) and return a default value if necessary and run the risk that the client programmer may never clue into the fact that something went wrong, leading to unexpected results (or worse) for the client code
• Check for the error condition and alert the client that something went wrong
Option 3 is by far the better approach!
How do we inform the client that something went wrong?
CPSC 252 Exception Handling Page 3
Notifying the client
Terminate the program and optionally print an error message
if ( !count ) {
cerr << “Queue is empty” << endl;
exit (-1);
}
else
• not great because the client cannot recover
Have the function return a bool indicating successful/failure
bool enqueue( const Item_type& item )
• reasonable when we know failure is expected at some point
• but not when something unexpected happens only seldomly
CPSC 252 Exception Handling Page 4
Or we can throw an exception…
C++ has a special mechanism for signaling failure
• any function can throw an exception when it detects an error
if ( count >= CAPACITY )
throw logic_error( “Queue is full” );
else
• this terminates the call to the function
• the client code then has the option of catching the exception
catch ( exception& e ) { [error handling] }
• the client might not catch the exception
• if it is not caught a default handler will terminate the program
CPSC 252 Exception Handling Page 5
What is an exception? Is it an int? Is it a char?
In C++, any kind of object can be thrown as an exception
• usually the variable that is thrown is a class
• these are designed specifically to act as exceptions
• C++ defines a set of these classes in the standard library
• the declarations are in the header file <exception>
exception
logic_error runtime_error
CPSC 252 Exception Handling Page 6
The what() method in the exception class
The exception class uses this to describe the error
• what() has the following signature
const char* what() const;
• what() returns a pointer to an error message
• the constructor has a string parameter for the message
We can create our own exception classes
• they are based on logic_error and runtime_error
• a logic_error indicates the client should know better
• a runtime_error indicates external cause
• a bad_alloc from new means no memory available
CPSC 252 Exception Handling Page 7
We define an exception that can be thrown when the dequeue function is called on an empty queue
We will call this exception AccessViolation to indicate that we are trying to access an element that does not exist
#include <exception>
#include <stdexcept> // probably includes <exception>using namespace std;
class AccessViolation : public logic_error{ AccessViolation( void )
: logic_error( “Access violation” ) { }};
The what() method is declared in the exception class
CPSC 252 Exception Handling Page 8
Now let’s think about how our dequeue() function will be written:
Item_type Queue::dequeue( void ){ if( isEmpty() ) // check if queue is empty throw AccessViolation();
// rest of function omitted, but it does // whatever we do if queue is not empty}
Here we call the constructor of the AccessViolation class to create an anonymous instance of the class and throw it
If the exception is thrown, the dequeue() function is terminated without executing any subsequent code in the function
CPSC 252 Exception Handling Page 9
How the client uses the exceptiontry{ while( true ) // Horrible! Should be myQueue.dequeue(); // checking precondition!
}catch( exception& e ){ cout << “Exception: ” << e.what() << endl;}
// now continue with rest of program
There are two subtleties here that we will not fully explain
• the object e is a reference to an exception
• the what() function retrieves “Access violation”
CPSC 252 Exception Handling Page 10
What this means to a client
Any code that
• calls a function that might throw an exception
• calls a function that calls a function that might throw an exception
• etc.
• should be wrapped in try-catch blocks
• we try to execute the code in the try-block
• if problems arise we let the catch-block handle it
This passes the responsibility for dealing with the error condition back to the client rather where it belongs
Do not to overuse this feature!
CPSC 252 Exception Handling Page 11
Some words of caution about exceptions
Note: If a function can reasonably handle the error condition itself then it should do so. An exception should be thrown only in the case where the function cannot be expected to handle the situation.
Note: The fact that a function throws an exception is not an excuse for the client to write sloppy code. Remember that an exception should be thrown only when something exceptional occurs.
Note: do not throw exceptions to “bail out” from situations that you as a programmer have difficulty resolving – for example, bailing out from a recursive call because you can’t think of any other way to do it gracefully!
CPSC 252 Exception Handling Page 12
Example of a use of exceptions (1)
Suppose the employee has two data members
• name – to represent the employee’s last name
• employeeNum - to represent the employee numberclass employee{ string name;
int employeeNum; };
Now suppose we want to write a function to read an employee from a file
We can run into two problems when we use the function:
• we hit the end of file so there is no more data to read
• the data in the file is not a valid employee number
CPSC 252 Exception Handling Page 13
Example of a use of exceptions (2)
The last situation will occur if the file contains the following data, for example:
Jones 3542Wong 4214Smith - 5434Ng 6785
• one of these situations is expected (the end of file)
• and the other (invalid format) is not
• we handle them accordingly
• a return value for end-of-file
• an exception for invalid data
CPSC 252 Exception Handling Page 14
Example of a use of exceptions (3)
bool readEmployee( ifstream& inStream, employee& next ){ inStream >> next.name; if( inStream.eof() ) return false; inStream >> next.employeeNum; if( inStream.fail() ) throw BadDataError();
return true;}
• the end-of-file is expected at some point
• we return a bool and let the client check the return value
• finding badly formatted data in the file is not expected
• we handle this situation by throwing an exception
CPSC 252 Exception Handling Page 15
Some of the fine details
We can have more than one catch block
• this allow us to catch different types of exceptions
We catch any type of exception
try{ // do something that might throw an exception
}catch( AccessViolation& excep ){ // do this if AccessViolation
}catch( exception& excep ){ // do this if some other exception class}catch( ... ){ // do this for any other type that is thrown}
CPSC 252 Exception Handling Page 16
Which catch block handles the exception?
If an exception is thrown from the try block, it is handled by the first catch block that can accept it based on its type
• in the previous example, if the exception that gets thrown is a AccessViolation the exception is handled by the first catch block (and only that block)
• if the exception that gets thrown cannot be handled by the first block it is tested against subsequent catch blocks
• if it cannot be handled by any of them, it is handled by the catch-all block.
• it is important to order catch blocks so that earlier blocks handle the more specific exceptions
• the catch-all block, if there is one, must always go last