Activity 17-3 - Throwing an Exception in a Function



Sometimes you may want to delay handling an exception.  For example, you may have a function with code that throws an exception if there is an attempt to divide by zero, but you may not want to catch the exception in that function.  This becomes an important issue because one program that uses this function should end if the exception is thrown, and other programs that use this function may want to do something else.  So in such cases, it makes sense to not catch the exception in the function definition, but instead to have any program that uses the function place the function invocation in a try-block and then catch the exception in a catch-block that follows that try-block.

Here is an example:

// P17_3.cpp - This program illustrates throwing an exception inside a function
#include <iostream>
#include <cstdlib>
using namespace std;

class DivideByZero
{};

double safe_divide(int top, int bottom) throw (DivideByZero);

int main()
{
    int numerator;
    int denominator;
    double quotient;
    cout << "Enter numerator:\n";
    cin >> numerator;
    cout << "Enter denominator:\n";
    cin >> denominator;

    try
    {
       quotient = safe_divide(numerator, denominator);
    }
    catch(DivideByZero)
    {
         cout << "Error: Division by zero!\n"
              << "Program aborting.\n";
         exit(0);
    }

    cout << numerator << "/" << denominator
         << " = " << quotient << endl;

    cout << "End of program.\n";
    return 0;
}

double safe_divide(int top, int bottom) throw (DivideByZero)
{
    if (bottom == 0)
        throw DivideByZero();

    return top/double(bottom);
}

In this program there is no throw statement visible in the try-block.  The statement that does the throwing in that program is:

    if (bottom == 0)
        throw DivideByZero();

and it is not visible in the try-block, however, it is in the try-block in terms of program execution.  If you look closely, you will see an if statement in the body of function safe_divide which will be invoked in the try-block.

Exception Specifications
If a function does not catch an exception, it should at least warn programmers that any invocation of the function might possibly throw an exception.  If there are exceptions that might be thrown, but not caught in the function definition, then those exception types should be listed in an exception specification, which is illustrated by the following:

double safe_divide(int top, int bottom) throw (DivideByZero);

The exception specification must appear in both the function declaration and the function definition.  If a function has more than one declaration, all function declarations must have the same exception specification.  The exception specification is also referred to as a throw-list.

If more than one exception is thrown in a function, then they are separated by commas:

void some_function( ) throw (DivideByZero, OtherException);

If an exception is thrown into a function but that function does not include the specification, then the program ends once it has reached the exception situation.

Exercise 17.3
The following program solves a quadratic equation.  Use the concepts that you have learned in this activity to rewrite the program such that it uses the exception handlers to handle exceptional situations.

// Program to solve quadratic equation
#include <iostream>
#include <cstdlib>
#include <cmath>

using namespace std;
void all_zero( );
void roots(double a, double b, double c);

int main( )
{
    double a, b, c; // coefficient of ax^2 + bx + c = 0
    cout << "Enter the three coefficients \n";
    cin >> a >> b >> c;

    roots(a, b, c);

    return 0;
}

void all_zero( )
{
    exit(1);
}

void roots(double a, double b, double c)
{
    double x1, x2; // The two roots
    double temp;

    if( !(a == 0 && b == 0 && c == 0) )
    {
        if(a != 0)
        {
            temp = b*b - 4*a*c;
            if(temp >= 0)
            {
                    // Two roots
                    x1 = ( -b + sqrt(temp))/2*a;
                    x2 = ( -b - sqrt(temp))/2*a;
                    cout << "The two roots are: " << x1 << " and " << x2 << endl;
            }
            else
            {
                    cout << "Square root of negative values is not defined \n";
                    exit(1);
            }

        }
        else
        {
            cout << "Division by zero, not defined \n";
            exit(1);
        }
 }
    else
    {
        all_zero( );
    }
}