error handling and exceptions - github pages · exceptions exceptions are used for dealing with...

23
Error Handling and Exceptions Stephen P Levitt School of Electrical and Information Engineering University of the Witwatersrand 2019

Upload: others

Post on 29-Jul-2020

22 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Error Handling and Exceptions

Stephen P Levitt

School of Electrical and Information EngineeringUniversity of the Witwatersrand

2019

Page 2: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

How Do We Deal With Errors?

double quotient(int num, int denom) // callee{return static_cast<double>(num)/denom;

}

int main() // caller{

int num1 = 0 , num2 = 0;cout << "Enter two integers: ";cin >> num1 >> num2;

double result = quotient(num1,num2);cout << "The quotient is: " << result << endl;

return 0;}

Error Handling and Exceptions 1 / 21

Page 3: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Output from Example

Enter two integers: 1 0The quotient is: 1.#INF

Error Handling and Exceptions 2 / 21

Page 4: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Outline

1 Understanding Errors

2 Error Handling Strategies — Using Exceptions

3 Errors During Object Construction

Error Handling and Exceptions 3 / 21

Page 5: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

What constitutes an error?

A function (a unit of work) cannot do what is asked of it:Precondition violation, eg. string :: insert (pos, string_to_insert )Postcondition violation, eg. string :: append(string_to_append)Invariant violationvoid Date::next() {// increment the date by one calendar day// ...

assert(day_ > 0 && day_ <= 31 && "Day is invalid" );}

If string::find_first_of cannot find a particular character in a string, is it anerror?

Error Handling and Exceptions : Understanding Errors 4 / 21

Page 6: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Technical and Domain Errors

Technical ErrorsCannot establish a connection to the databaseCannot open a file for writing

Domain ErrorsInsufficient funds for transferProduct barcode not found in database

Error Handling and Exceptions : Understanding Errors 5 / 21

Page 7: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Error Handling and Propagation Strategies

Assume that an error occurs in a function. The options for signalling this error to theclient code are:

1 Don’t propagate the error; log it and/or terminate the program2 Return a value representing “error”3 Return a legal value but set a global variable to record the error condition4 Throw an exception

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 6 / 21

Page 8: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Exceptions

Exceptions are used for dealing with run-time errorsExamples include: the failure of new to obtain a requested amount of memory, anout of bounds array subscript, arithmetic overflow

Exceptions allow for:The generation of an error notification for an issue that cannot be resolved locally— a function which finds a problem that it cannot cope with throws an exception.The handling of an error detected elsewhere — the function in question hopes thatits direct or indirect caller can catch or handle the problem.

This is important when a program is composed of separate modules/layers, oruses libraries.

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 7 / 21

Page 9: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Exceptions

Exceptions are used for dealing with run-time errorsExamples include: the failure of new to obtain a requested amount of memory, anout of bounds array subscript, arithmetic overflowExceptions allow for:

The generation of an error notification for an issue that cannot be resolved locally— a function which finds a problem that it cannot cope with throws an exception.The handling of an error detected elsewhere — the function in question hopes thatits direct or indirect caller can catch or handle the problem.

This is important when a program is composed of separate modules/layers, oruses libraries.

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 7 / 21

Page 10: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Using Exceptions in the Earlier Example

To improve matters modify the function’s code so that it throws an exception:

double quotient( int num, int denom ){

if (denom == 0)throw denom; // throw the denominator

return static_cast<double>(num)/denom;}

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 8 / 21

Page 11: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Using Exceptions - The try Block

The client code can now handle any errors generated with try and catch:

int main(){

cout << "Enter two integers: ";auto num1 = 0, num2 = 0;

while ( cin >> num1 >> num2 ) {

// the try block wraps the code that may throw an exceptiontry{

cout << "The quotient is: " << quotient(num1, num2) << endl;}

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 9 / 21

Page 12: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Using Exceptions - The catch Block

// exception handler - has the form of a function signaturecatch (int denom){cout << "Exception occurred: Attempt to divide by " << denom <<

endl;}

cout << "Enter two integers: ";}

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 10 / 21

Page 13: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Output from Example 3

Enter two integers: 1 0Exception occurred: Attempted to divide by zeroEnter two integers:

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 11 / 21

Page 14: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Prefer Throwing User-Defined Exceptions

Throwing primitive or built-in types is likely to lead to clashes with other exceptionhandlers

class DivideByZeroException {public:

DivideByZeroException(): message_("Attempted to divide by zero"){ }

string message() const { return message_; }

private:string message_;

};

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 12 / 21

Page 15: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Prefer Throwing User-Defined Exceptions

quotient throws DivideByZeroException

double quotient( int num, int denom ){

if ( denom == 0 )throw DivideByZeroException{}; // construct unnamed temporary

return static_cast<double>(num)/denom;}

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 13 / 21

Page 16: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Prefer Throwing User-Defined Exceptions - main

int main(){

cout << "Enter two integers: ";auto num1 = 0, num2 = 0;

while ( cin >> num1 >> num2 ) {try { // wraps code that may throw an exception

cout << "The quotient is: " << quotient(num1, num2) << endl;}// Catch by constant referencecatch (const DivideByZeroException& ex) { // exception handler

cout << "Exception occurred: " << ex.message() << endl;}cout << "Enter two integers: ";

}return 0;

}Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 14 / 21

Page 17: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Catching Dynamic Memory Allocation ExceptionsOperator new throws an exception object of type bad_alloc. bad_alloc is a class.

int main() {long int size = 0;try {

while (true) {char* p = new char;++size;

}}

catch(const bad_alloc& b) { cout << "Memory exhausted!"; }

cout << "Free store (heap) size: " << size;return 0;

}

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 15 / 21

Page 18: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Catching All and Sundrycatch clauses are examined in turn, in the order in which they appear followingthe try block.Once a match is found subsequent catch clauses are not examined.

try{ // main programme code }

catch(const bad_alloc& b){ }

catch (const DivideByZeroException& ex){ }

// must be last catch clausecatch(...){ }

Error Handling and Exceptions : Error Handling Strategies — Using Exceptions 16 / 21

Page 19: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Exceptions and Constructors

Consider the following:

class AddressBookEntry {public:...

private:// ptr to the person's imageImage* image_ptr_;// ptr the person's voice recordingAudioClip* audio_ptr_;

};

Error Handling and Exceptions : Errors During Object Construction 17 / 21

Page 20: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Exceptions and Constructors cont.

AddressBookEntry::AddressBookEntry(const string& image_filename,const string& audio_filename):image_ptr_{nullptr},audio_ptr_{nullptr}

{// dynamically allocate memory for Imageif (image_filename != "") image_ptr_ = new Image{image_filename};

// dynamically allocate memory for AudioClipif (audio_filename != "") audio_ptr_ = new AudioClip{audio_filename};}

Error Handling and Exceptions : Errors During Object Construction 18 / 21

Page 21: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

AddressBookEntry’s Destructor

// AddressBookEntry DestructorAddressBookEntry::~AddressBookEntry(){

// in AddressBookEntry destructordelete image_ptr_;image_ptr_ = nullptr;

delete audio_ptr_;audio_ptr_ = nullptr;

}

Error Handling and Exceptions : Errors During Object Construction 19 / 21

Page 22: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Exceptions and Constructors — Solution

C++ only destroys fully constructed objects, and an object is only fullyconstructed when the constructor has run to completionLocal objects (created on the stack) are automatically destroyed whenever they goout of scope

class AddressBookEntry {public:...

private:// now using smart pointersunique_ptr<Image> image_ptr_;unique_ptr<AudioClip> audio_ptr_;

};

Error Handling and Exceptions : Errors During Object Construction 20 / 21

Page 23: Error Handling and Exceptions - GitHub Pages · Exceptions Exceptions are used for dealing with run-time errors Examples include: the failure of newto obtain a requested amount of

Exceptions and Constructors — Solution

AddressBookEntry::AddressBookEntry(const string& image_filename,const string& audio_filename)// default constructor called for image, audio ptrs

{// dynamically allocate memory for Imageif (image_filename != "") image_ptr_ =

make_unique<Image>(image_filename);

// dynamically allocate memory for AudioClipif (audio_filename != "") audio_ptr_ =

make_unique<AudioClip>(audio_filename);}

Exceptions — An important reason to use smart pointers

Error Handling and Exceptions : Errors During Object Construction 21 / 21