Механизм исключительных ситуаций базируется на ключевых словах 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. Обработка ошибок и исключения
К сожалению, здесь возникает несколько проблем. Во-первых, хотя результат факториала не может быть отрицательным, другим функциям повезло гораздо меньше. Например, вы не можете взять логарифм от отрицательного числа, но сам логарифм может быть как отрицательным, так и положительным, а поэтому возврат отрицательного числа не обязательно будет означать ошибку.