17.2.4 Defining a catch Handler to Process a DivideByZeroException

You saw in Section 7.10 that exceptions are processed by catch handlers. At least one catch handler (lines 34–37) must immediately follow each try block. An exception parameter should always be declared as a reference to the type of exception the catch handler can process (DivideByZeroException in this case)—this prevents copying the exception object when it’s caught and allows a catch handler to properly catch derived-class exceptions as well.

When an exception occurs in a try block, the catch handler that executes is the first one whose type matches the type of the exception that occurred (i.e., the type in the catch block matches the thrown exception type exactly or is a direct or indirect base class of it). If an exception parameter includes an optional parameter name, the catch handler can use that parameter name to interact with the caught exception in the body of the catch handler, which is delimited by braces ({ and }).

A catch handler typically reports the error to the user, logs it to a file, terminates the program gracefully or tries an alternate strategy to accomplish the failed task. In this example, the catch handler simply reports that the user attempted to divide by zero. Then the program prompts the user to enter two new integer values.

Common Programming Error 17.1

It’s a syntax error to place code between a try block and its corresponding catch handlers or between its catch handlers.

 

Common Programming Error 17.2

Each catch handler can have one parameter—specifying a comma-separated list of exception parameters is a syntax error.

 

Common Programming Error 17.3

It’s a compilation error to catch the same type in multiple catch handlers following a single try block.

17.2.5 Termination Model of Exception Handling

If an exception occurs as the result of a statement in a try block, the try block expires (i.e., it terminates immediately). Next, the program searches for the first catch handler that can process the type of exception that occurred. The program locates the matching catch by comparing the thrown exception’s type to each catch’s exception-parameter type until the program finds a match. A match occurs if the types are identical or if the thrown exception’s type is a derived class of the exception-parameter type.

When a match occurs, the code in the matching catch handler executes. When a catch handler finishes processing by reaching its closing right brace (}), the exception is considered handled and the local variables defined within the catch handler (including the catch parameter) go out of scope. Program control does not return to the point at which the exception occurred (known as the throw point), because the try block has expired. Rather, control resumes with the first statement (line 39 in Fig. 17.2) after the last catch handler following the try block. This is known as the termination model of exception handling. Some languages use the resumption model of exception handling, in which, after an exception is handled, control resumes just after the throw point. As with any other block of code, when a try block terminates, local variables defined in the block go out of scope.

Common Programming Error 17.4

Logic errors can occur if you assume that after an exception is handled, control will return to the first statement after the throw point.

 

Error-Prevention Tip 17.2

With C++ exception handling, a program can continue executing (rather than terminating) after dealing with a problem. This helps ensure the kind of robust applications that contribute to what’s called mission-critical computing or business-critical computing.

If the try block completes its execution successfully (i.e., no exceptions occur in the try block), then the program ignores the catch handlers and program control continues with the first statement after the last catch following that try block.

If an exception occurs in a function and is not caught in that function, the function terminates immediately, and the program attempts to locate an enclosing try block in the calling function. This process is called stack unwinding and is discussed in Section 17.4.

17.2.6 Flow of Program Control When the User Enters a Nonzero Denominator

Consider the flow of control in Fig. 17.2 when the user inputs the numerator 100 and the denominator 7. In line 12, function quotient determines that the denominator is not zero, so line 17 performs the division and returns the result (14.2857) to line 31 as a double. Program control then continues sequentially from line 31, so line 32 displays the division result—line 33 ends the try block. Because the try block completed successfully (no exception was thrown), the program does not execute the statements contained in the catch handler (lines 34–37), and control continues to line 39 (the first line of code after the catch handler), which prompts the user to enter two more integers.

17.2.7 Flow of Program Control When the User Enters a Denominator of Zero

Now consider the case in which the user inputs the numerator 100 and the denominator 0. In line 12, quotient determines that the denominator is zero, which indicates an attempt to divide by zero. Line 13 throws an exception, which we represent as an object of class DivideByZeroException (Fig. 17.1).

To throw an exception, line 13 in Fig. 17.2 uses keyword throw followed by an operand of the type of exception to throw. Normally, a throw statement specifies one operand. (In Section 17.3, we discuss how to use a throw statement with no operand.) The operand of a throw can be of any copy-constructible type. If the operand is an object, we call it an exception object—in this example, the exception object is of type DivideByZeroException. However, a throw operand also can assume other values, such as the value of an expression that does not result in an object of a class (e.g., throw x > 5) or the value of an int (e.g., throw 5). The examples in this chapter throw objects of exception classes.

Error-Prevention Tip 17.3

In general, you should throw only objects of exception class types.

As part of throwing an exception, the throw operand is created and used to initialize the parameter in the catch handler, which we discuss momentarily. The throw statement in line 13 creates a DivideByZeroException object. When line 13 throws the exception, function quotient exits immediately. So, line 13 throws the exception before function quotient can perform the division in line 17.

Software Engineering Observation 17.4

A central characteristic of exception handling is: If your program explicitly throws an exception, it should do so before the error has an opportunity to occur.

Because we enclosed the call to quotient (line 31) in a try block, program control enters the catch handler (lines 34–37) that immediately follows the try block. This catch handler serves as the exception handler for the divide-by-zero exception. In general, when an exception is thrown within a try block, the exception is caught by a catch handler that specifies the type matching the thrown exception. In this program, the catch handler specifies that it catches DivideByZeroException objects—this type matches the object type thrown in function quotient. Actually, the catch handler catches a reference to the DivideByZeroException object created by function quotient’s throw statement (line 13), so that the catch handler does not make a copy of the exception object.

The catch’s body (lines 35–36) prints the error message returned by function what of base-class runtime_error—i.e., the string that the DivideByZeroException constructor (lines 10–11 in Fig. 17.1) passed to the runtime_error base-class constructor.

Good Programming Practice 17.1

Associating each type of runtime error with an appropriately named exception type improves program clarity.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset