0% found this document useful (0 votes)
11 views6 pages

C++ Error Handling with Assertions

The document discusses the use of assertions in C++ to catch elusive errors like division by zero, providing a mechanism to halt program execution with an error message. It also covers exception handling techniques, including terminating the program, fixing errors and continuing, and logging errors while continuing execution. Additionally, it introduces C++ exception classes for handling logical and runtime errors, along with practical lab tasks for implementing these concepts.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views6 pages

C++ Error Handling with Assertions

The document discusses the use of assertions in C++ to catch elusive errors like division by zero, providing a mechanism to halt program execution with an error message. It also covers exception handling techniques, including terminating the program, fixing errors and continuing, and logging errors while continuing execution. Additionally, it introduces C++ exception classes for handling logical and runtime errors, along with practical lab tasks for implementing these concepts.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Assertions

Certain types of errors that are very difficult to catch can occur in a program. For example,
division by zero can be difficult to catch using any of the programming techniques you have
examined so far. C++ includes a predefined function, assert, that is useful in stopping program
execution when certain elusive errors occur. In the case of division by zero, you can use the
assert function to ensure that a program terminates with an appropriate error message
indicating the type of error and the program location where the error occurred.
Consider the following statements:
int numerator;
int denominator;
int quotient;
double hours;
double rate;
double wages;
char ch;
1. quotient = numerator / denominator;
2. if (hours > 0 && (0 < rate && rate <= 15.50)) wages = rate * hours;
3. if ('A' <= ch && ch <= 'Z')
In the first statement, if the denominator is 0, logically you should not perform the division.
During execution, however, the computer would try to perform the division. If the denominator
is 0, the program would terminate with an error message stating that an illegal operation has
occurred.
The second statement is designed to compute wages only if hours is greater than 0and rate is
positive and less than or equal to 15.50. The third statement is designed to execute certain
statements only if ch is an uppercase letter.
For all of these statements (for that matter, in any situation), if conditions are not met, it would
be useful to halt program execution with a message indicating where in the program an error
occurred. You could handle these types of situations by including output and return statements
in your program. However, C++ provides an effective method to halt a program if required
conditions are not met through the assert function.
The syntax to use the assert function is:
assert(expression);

Here, expression is any logical expression. If expression evaluates to true, the next statement
executes. If expression evaluates to false, the program terminates and indicates where in the
program the error occurred.
The specification of the assert function is found in the header file cassert. Therefore, for a
program to use the assert function, it must include the following statement:
#include <cassert>
A statement using the assert function is sometimes called an assert statement. eturning to the
preceding statements, you can rewrite statement 1 (quotient = numerator / denominator;)
using the assert function. Because quotient should be calculated only if denominator is
nonzero, you include an assert statement before the assignment statement as follows:
assert(denominator);
quotient = numerator / denominator;
Now, if denominator is 0, the assert statement halts the execution of the program with an error
message similar to the following:
Assertion failed: denominator, file c:\temp\assert
function\[Link], line 20
This error message indicates that the assertion of denominator failed. The error message also
gives the name of the file containing the source code and the line number where the assertion
failed.
For readability, the previous code using the assert statement can also be written as:
assert(denominator != 0);
quotient = numerator / denominator;
The error message would be slightly different:
Assertion failed: denominator != 0, file c:\temp\assert
function\[Link], line 20
You can also rewrite statement 2 using an assertion statement as follows:
assert(hours > 0 && (0 < rate && rate <= 15.50));
if (hours > 0 && (0 < rate && rate <= 15.50))
wages = rate * hours;
If the expression in the assert statement fails, the program terminates with an error message
similar to the following:
Assertion failed: hours > 0 && (0 < rate && rate <= 15.50), file
c:\temp\assertfunction\[Link], line 26
During program development and testing, the assert statement is very useful for enforcing
programming constraints. As you can see, the assert statement not only halts the program, but
also identifies the expression where the assertion failed, the name of the file containing the source
code, and the line number where the assertion failed.
Although assert statements are useful during program development, after a program has been
developed and put into use, if an assert statement fails for some reason, an end user would have
no idea what the error means. Therefore, after you have developed and tested a program, you
might want to remove or disable the assert statements. In a very large program, it could be
tedious, and perhaps impossible, to remove all of the assert statements that you used during
development. In addition, if you plan to modify a program in the future, you might like to keep
the assert statements. Therefore, the logical choice is to keep these statements but to disable
them.
You can disable assert statements by using the following pre-processor directive:
#define NDEBUG
This preprocessor directive #define NDEBUG must be placed before the directive #include
<cassert>.

Lab Task
1. Write a Program that takes as input the lengths of three sides a, b, c of a triangle and
determine if it is equilateral, isosceles or scalene. Use assertions to terminate the program
if any invalid input is entered. Suppose the lengths a, b and c can have a valid value from
1 to 100.
Exceptions
An exception is an occurrence of an undesirable situation that can be detected during program
execution. For example, division by zero is an exception. Similarly, trying to open an input file that
does not exist is an exception, as is an array index that goes out of bounds.
There are situations when an exception occurs, but you don’t want the program to simply ignore
the exception and terminate. For example, a program that monitors stock performance should
not automatically sell if the account balance goes below a certain level. It should inform the
stockholder and request an appropriate action.
Similarly, a program that monitors a patient’s heartbeat cannot be terminated if the blood
pressure goes very high. A program that monitors a satellite in space cannot be terminated if
there is a temporary power failure in some section of the satellite.

Exception Handling Techniques


When an exception occurs in a program, the programmer usually has three choices: terminate the
program, include code in the program to recover from the exception, or log the error and
continue. The following sections discuss each of these situations.
Terminate the Program
In some cases, it is best to let the program terminate when an exception occurs. Suppose you have
written a program that inputs data from a file. If the input file does not exist when the program
executes, then there is no point in continuing with the program. In this case, the program can
output an appropriate error message and terminate.

// Handling division by zero exception.


#include <iostream> //Line 1
using namespace std; //Line 2
int main() //Line 3
{ //Line 4
int dividend, divisor, quotient; //Line 5
try //Line 6
{ //Line 7
cout << "Line 8: Enter the dividend: "; //Line 8
cin >> dividend; //Line 9
cout << endl; //Line 10
cout << "Line 11: Enter the divisor: "; //Line 11
cin >> divisor; //Line 12
cout << endl; //Line 13
if (divisor == 0) //Line 14
throw 0; //Line 15
quotient = dividend / divisor; //Line 16
cout<< "Line 17: Quotient=" << quotient << endl; //Line 17
} //Line 18
catch (int) //Line 19
{ //Line 20
cout << "Line 21: Division by 0." << endl; //Line 21
} //Line 22
return 0; //Line 23
} //Line 24
Fix the Error and Continue
In other cases, you will want to handle the exception and let the program continue. Suppose that
you have a program that takes as input an integer. If a user inputs a letter in place of a number,
the input stream will enter the fail state. This is a situation in which you can include the necessary
code to keep prompting the user to input a number until the entry is valid.
// Handle exceptions by fixing the errors. The program
// continues to prompt the user until a valid input is entered.

#include <iostream> //Line 1


using namespace std; //Line 2
int main() //Line 3
{ //Line 4
int number; //Line 5
bool done = false; //Line 6
char str[] = "The input stream is in the fail state."; //Line 7
do //Line 8
{ //Line 9
try //Line 10
{ //Line 11
cout << "Line 12: Enter an integer: "; //Line 12
cin >> number; //Line 13
cout << endl; //Line 14
if (!cin) //Line 15
throw str; //Line 16
done = true; //Line 17
cout<< "Line 18:Number="<< number << endl; //Line 18
} //Line 19
catch (const char messageStr[]) //Line 20
{ //Line 21
cout<<"Line 22: " << messageStr << endl; //Line 22
cout<<"Line 23:Restoring input stream"<<endl; //Line 23
[Link](); //Line 24
[Link](100, '\n'); //Line 25
} //Line 26
} //Line 27
while (!done); //Line 28
return 0; //Line 29
} //Line 30

This program prompts the user to enter an integer. If the input is invalid, the standard input
stream enters the fail state. In the try block, the statement in Line 16 throws an exception, which
is a string. Control passes to the catch block, and the exception is caught and processed. The
statement in Line 24 restores the input stream to its good state, and the statement in Line 25
clears the rest of the input from the line. The do. . .while loop continues to prompt the user until
the user inputs a valid number.
Log the Error and Continue
The program that terminates when an exception occurs usually assumes that this termination is
reasonably safe. However, if your program is designed to run a nuclear reactor or continuously
monitor a satellite, it cannot be terminated if an exception occurs. These programs should report
the exception, but the program must continue to run.
For example, consider a program that analyzes an airline’s ticketing transactions. Because
numerous ticketing transactions occur each day, a program is run at the end of each day to
validate that day’s transactions. This type of program would take an enormous amount of time to
process the transactions and use exceptions to identify any erroneous entries. Instead, when an
exception occurs, the program should write the exception into a file and continue to analyze the
transactions.

Using C++ Exception Classes


C++ provides support to handle exceptions via a hierarchy of classes. The class exception is
the base of the classes designed to handle exceptions. Among others, this class contains the
function what. The function what returns a string containing an appropriate message. All derived
classes of the class exception override the function what to issue their own error messages.
Two classes are immediately derived from the class exception: logic_error and
runtime_error. Both of these classes are defined in the header file stdexcept. To deal with
logical errors in a program, such as a string subscript out of range or an invalid argument to a
function call, several classes are derived from the class logic_error. For example, the class
invalid_argument is designed to deal with illegal arguments used in a function call. The class
out_of_range deals with the string subscript out of range error. If a length greater than the
maximum allowed for a string object is used, the class length_error deals with this error. For
example, recall that every string object has a maximum length. If a length larger than the
maximum length allowed for a string is used, then the length_error exception is generated. If
the operator new cannot allocate memory space, this operator throws a bad_alloc exception.
The class runtime_error is designed to deal with errors that can be detected only during
program execution. For example, to deal with arithmetic overflow and underflow exceptions, the
classes overflow_error and underflow_error are derived from the class runtime_error.
The program in the following example shows how to handle the exceptions out_of_range and
length_error. Notice that in this program, these exceptions are thrown by the string functions
substr and the string concatenation operator +. Because the exceptions are thrown by these
functions, we do not include any throw statement in the try block.

// Handling out_of_range and length_error exceptions.


#include <iostream> //Line 1
#include <string> //Line 2
using namespace std; //Line 3
int main() //Line 4
{ //Line 5
string sentence; //Line 6
string str1, str2, str3; //Line 7
try //Line 8
{ //Line 9
sentence = "Testing string exceptions!"; //Line 10
cout << "Line 11: sentence = " << sentence << endl; //Line 11
cout << "Line 12: [Link]() = " << //Line 12
static_cast<int>([Link]()) << endl;
str1 = [Link](8, 20); //Line 13
cout << "Line 14: str1 = " << str1 << endl; //Line 14
str2 = [Link](28, 10); //Line 15
cout << "Line 16: str2 = " << str2 << endl; //Line 16
str3 = "Exception handling. " + sentence; //Line 17
cout << "Line 18: str3 = " << str3 << endl; //Line 18
} //Line 19
catch (out_of_range re) //Line 20
{ //Line 21
cout << "Line 22: In the out_of_range catch" << " block: //Line 22
" << [Link]() << endl;
} //Line 23
catch (length_error le) //Line 24
{ //Line 25
cout << "Line 26: In the length_error catch" << " block: //Line 26
" << [Link]() << endl;
} //Line 27
return 0; //Line 28
} //Line 29
In this program, the statement in Line 13 uses the function substr to determine a substring in
the string object sentence. The length of the string sentence is 26. Because the starting position
of the substring is 8, which is less than 26, no exception is thrown. However, in the statement in
Line 15, the starting position of the substring is 28, which is greater than 26 (the length of
sentence). Therefore, the function substr throws an out_of_range exception, which is caught
and processed by the catch block in Line 20. Notice that in the statement in Line 22, the object
re uses the function what to return the error message, invalid string position.

Lab Task
1. Write a program that prompts the user to enter a length in feet and inches and outputs
the equivalent length in centimeters. If the user enters a negative number or a non-digit
number, throw and handle an appropriate exception and prompt the user to enter
another set of numbers.
2. Write a program that prompts the user to enter a person’s date of birth in numeric form
such as 8-27-1980. The program then outputs the date of birth in the form: August 27,
1980. Your program must contain at least two exception classes: invalidDay and
invalidMonth. If the user enters an invalid value for day, then the program should throw
and catch an invalidDay object. Follow similar conventions for the invalid values of
month and year. (Note that your program must handle a leap year.)
3. Write a program that takes as input the lengths of three sides a, b, c of a triangle and
determine if it is equilateral, isosceles or scalene. The program should throw an exception
if the entered values do not make a triangle. (Recall that each side of triangle is less than
the sum of the other two sides.) After the exception is thrown the program should fix the
error and continue i.e. it should take the input again until the valid values are entered.

References
C++ Programming: From Problem Analysis to Program Design (8th Edition) by D S Malik

You might also like