Выбрать главу

Механизм исключительных ситуаций базируется на ключевых словах try ( попытаться, пробовать, попытка [trai] [трай] ), throw ( бросить, бросание, бросок —   [θrou] — [сроу] ) и catch (  поймать, схватить, ловить [kætʃ] [кэчь] ). В общих чертах этот механизм работает так: функция пытается ( пробует — try ) выполнить фрагмент кода. Если в коде содержится ошибка, функция бросает ( генерирует — throw ) сообщение об ошибке, которое должна поймать ( перехватить — catch ) вызывающая функция. Это продемонстрировано в приведённой ниже программе.

    //

    /* FactorialException — демонстрация исключений */

    /*                  при использовании факториала */

    //

    #include <cstdio>

    #include <cstdlib>

    #include <iostream>

    #include <string>

    using namespace std ;

    /* factorial — вычисление факториала */

    int factorial( int n )

    {

        /* Функция не обрабатывает отрицательные  значения аргумента */

        if ( n < 0 )

        {

            throw string( "Аргумент отрицателен" ) ;

        }

        /* Вычисляем факториал */

        int accum = 1 ;

        while ( n > 0 )

        {

            accum *= n ;

_________________

290 стр. Часть 5. Полезные особенности

            n-- ;

        }

        return accum ;

    }

    int main( int nNumberofArgs , char* pszArgs[ ] )

    {

            /* печать кириллицы, если Вы не установите программки gccrus.exe и g++rus.exe */

            setlocale ( LC_ALL , ".1251" ) ;

        try

        {

            /* Здесь всё в порядке */

            cout << "3! = " << factorial( 3 ) << endl ;

            /* Здесь генерируется исключение */

            cout << "-1!= " << factorial( -1 ) << endl ;

            /* Этот код так и  остаётся не выполнен */

            cout << "Factorial of 5 is " << factorial( 5 )

                  << endl ;

        }

        /* Обработка исключения */

        catch( string error )

        {

            cout << "Ошибка: " << error << endl ;

        }

        catch ( ... )

        {

            cout << "Неизвестное исключение" << endl ;

        }

        /* Пауза для того, чтобы посмотреть на результат работы программы */

        system( "PAUSE" ) ; return 0 ;

    }

Функция main( ) начинается с блока, выделенного ключевым словом try. В этом блоке выполнение кода ничем не отличается от выполнения вне блока. В данном случае main( ) пытается вычислить факториал отрицательного числа. Однако функцию factorial( ) не так легко одурачить, поскольку она достаточно умно написана и обнаруживает, что запрос некорректен. При этом она генерирует сообщение об ошибке с помощью ключевого слова throw. Управление передаётся фрагменту, находящемуся сразу за закрывающей фигурной скобкой блока try и отвечающему за перехват сообщения об ошибке. Следующий за ошибочным вызов функции factorial так и не выполняется.

►Зачем, нужен новый механизм обработки ошибок...291

Что плохого в методе возврата ошибки, подобном применяемому в FORTRAN? Факториал не может быть отрицательным, поэтому я мог бы сказать что-то вроде: "Если функция factorial( ) обнаруживает ошибку, она возвращает отрицательное число. Значение отрицательного числа будет указывать на источник проблемы". Чем же плох такой метод? Ведь так было всегда.

_________________

291 стр. Глава 25. Обработка ошибок и исключения

К сожалению, здесь возникает несколько проблем. Во-первых, хотя результат факториала не может быть отрицательным, другим функциям повезло гораздо меньше. Например, вы не можете взять логарифм от отрицательного числа, но сам логарифм может быть как отрицательным, так и положительным, а поэтому возврат отрицательного числа не обязательно будет означать ошибку.