Let’s consider a simple example of exception handling (Figs. 17.1–17.2). For demonstration purposes, we show how to deal with a common arithmetic problem—division by zero, which with integer arithmetic typically causes a program to terminate prematurely. In floating-point arithmetic, many C++ implementations allow division by zero, in which case a result of positive or negative infinity is typically displayed as inf
or -inf
, respectively. Typically, a program would simply test for division by zero before attempting the calculation—we use exceptions here to present the flow of control when a program executes successfully and when an exception occurs.
In this example, we define a function quotient
that receives two integers entered by the user and divides the first by the second. Before performing the division, the function casts the first int
parameter’s value to type double
. Then, the second int
parameter’s value is (implicitly) promoted to type double
for the calculation. So function quotient
actually performs the division using two double
values and returns a double
result.
For the purpose of this example we treat any attempt to divide by zero as an error. Thus, function quotient
tests its second parameter to ensure that it isn’t zero before allowing the division to proceed. If the second parameter is zero, the function throws an exception to indicate to the caller that a problem occurred. The caller (main
in this example) can then handle the exception and allow the user to type two new values before calling function quotient
again. In this way, the program can continue executing even after an improper value is entered, thus making the program more robust.
The example consists of two files. DivideByZeroException.h
(Fig. 17.1) defines an exception class that represents the type of the problem that might occur in the example, and fig17_02.cpp
(Fig. 17.2) defines the quotient
function and the main
function that calls it—we’ll use quotient
and main
to explain the exception-handling flow of control.
Figure 17.1 defines class DivideByZeroException
as a derived class of Standard Library class runtime_error
(from header <stdexcept>
). Class runtime_error
—a derived class of exception
(from header <exception>
)—is the C++ standard base class for representing runtime errors. Class exception
is the standard C++ base class for exceptions in the C++ Standard Library. (Section 17.10 discusses class exception
and its derived classes in detail.) A typical exception class that derives from the runtime_error
class defines only a constructor (e.g., lines 10–11) that passes an error-message string to the base-class runtime_error
constructor. Every exception class that derives directly or indirectly from exception
contains the virtual
function what
, which returns an exception object’s error message. You’re not required to derive a custom exception class, such as DivideByZeroException
, from the standard exception classes provided by C++. However, doing so allows you to use the virtual
function what
to obtain an appropriate error message and also allows you to polymorphically process the exceptions by catching a reference to the base-class type. We use an object of this DivideByZeroException
class in Fig. 17.2 to indicate
when an attempt is made to divide by zero.
Figure 17.2 uses exception handling to wrap code that might throw a DivideByZeroException
and to handle that exception, should one occur. The user enters two integers, which are passed as arguments to function quotient
(lines 10–18). This function divides its first parameter (numerator
) by its second parameter (denominator
). Assuming that the user does not specify 0
as the denominator for the division, function quotient
returns the division result. If the user inputs 0
for the denominator, quotient
throws an exception. In the sample output, the first two lines show a successful calculation, and the next two show a failure due to an attempt to divide by zero. When the exception occurs, the program informs the user of the mistake and prompts the user to input two new integers. After we discuss the code, we’ll consider the user inputs and flow of program control that yield these outputs.
try
BlockThe program begins by prompting the user to enter two integers. The integers are input in the condition of the while
loop (line 27). Line 31 passes the values to function quotient
(lines 10–18), which either divides the integers and returns a result, or throws an exception (i.e., indicates that an error occurred) on an attempt to divide by zero. Exception handling is geared to situations in which the function that detects an error is unable to handle it.
As you learned in Section 7.10, try
blocks enable exception handling, enclosing statements that might cause exceptions and statements that should be skipped if an exception occurs. The try
block in lines 30–33 encloses the invocation of function quotient
and the statement that displays the division result. In this example, because the invocation of function quotient
(line 31) can throw an exception, we enclose this function invocation in a try
block. Enclosing the output statement (line 32) in the try
block ensures that the output will occur only if function quotient
returns a result.
Exceptions may surface through explicitly mentioned code in a try
block, through calls to other functions (including library calls), through deeply nested function calls initiated by code in a try
block and through operators like new
(Section 17.8).