Стефан Дэвис - С++ для чайников .
- Название:С++ для чайников .
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс. Компьютерное издательство Диалектика
- Год:2007
- Город:Москва
- ISBN:0-7645-6852-3, 978-5-8459-0723-3
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стефан Дэвис - С++ для чайников . краткое содержание
1
empty-line
4
С++ для чайников . - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
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. Обработка ошибок и исключения
К сожалению, здесь возникает несколько проблем. Во-первых, хотя результат факториала не может быть отрицательным, другим функциям повезло гораздо меньше. Например, вы не можете взять логарифм от отрицательного числа, но сам логарифм может быть как отрицательным, так и положительным, а поэтому возврат отрицательного числа не обязательно будет означать ошибку.
Во-вторых, в целочисленной переменной не передашь много информации. Можно, конечно, обозначить ситуацию "аргумент отрицательный" как - 1, ситуацию "аргумент слишком большой" как - 2 и т.д. Но если аргумент слишком большой, я хотел бы знать, какой именно, поскольку это поможет мне найти источник проблемы. Однако в целочисленной переменной такую информацию не сохранишь.
В-третьих, проверка возвращаемого значения вовсе не обязательна. Чтобы понять, что я имею в виду, представьте себе, что кто-то написал функцию factorial( ) , которая послушно проверяет, находится ли её аргумент в допустимых границах. Однако, если код, вызвавший эту функцию, не будет проверять возвращаемое значение, это не приведёт ни к чему хорошему. Конечно, я мог бы ввести в функцию всякие страшные угрозы наподобие "Вы обязательно должны проверить сообщения об ошибках, иначе...", но, думаю, не стоит объяснять, что язык не может никого ни к чему принудить.
Даже если моя функция проверяет наличие ошибки в factorial( ) или любой другой функции, что она может с ней сделать? Пожалуй, только вывести сообщение об ошибке ( которое я сам написал ) и вернуть другое значение, указывающее на наличие ошибки, вызывающей функцию, которая, скорее всего, повторит весь этот процесс. В результате программа будет переполнена кодом, подобным приведённому ниже.
errRtn = someFunc( ) ;
if ( errRtn )
{
errorOut( "Ошибка при вызове someFn( )" ) ;
return MY_ERROR_1
}
errRtn = someOtherFunc( ) ;
if ( errRtn )
{
errorOut( "Ошибка при вызове someOtherFn( )" ) ;
return MY_ERROR_1
}
Такой механизм имеет ряд недостатков.
■■■
■ Изобилует повторениями.
■ Заставляет программиста отслеживать множество разных ошибок и писать код для обработки всех возможных вариантов.
■ Смешивает код, отвечающий за обработку ошибок, с обычным кодом, что не добавляет ясности программе.
■■■
Эти недостатки кажутся безобидными в простом примере, но могут превратиться в большие проблемы, когда программа станет более сложной. В результате такой подход приводит к тому, что обработкой ошибок занимается 90% кода.
Механизм исключительных ситуаций позволяет обойти эти проблемы, отделяя код обработки ошибок от обычного кода. Кроме того, наличие исключений делает обработку ошибок обязательной. Если ваша функция не обрабатывает сгенерированное исключение, управление передаётся далее по цепочке вызывающих функций, пока С++ не найдёт функцию, которая обработает возникшую проблему. Это также даёт возможность игнорировать ошибки, которые вы не в состоянии обработать.
_________________
292 стр. Часть 5. Полезные особенности
►Механизм исключительных ситуаций...293
Познакомимся поближе с тем, как программа обрабатывает исключительную ситуацию. При возникновении исключения ( throw ) С++ первым делом копирует сгенерированный объект в некоторое нейтральное место. После этого просматривается конец текущего блока try .
Если блок try в данной функции не найден, управление передаётся вызывающей функции, где и осуществляется поиск обработчика. Если и здесь не найден блок try , поиск повторяется далее, вверх по стеку вызывающих функций. Этот процесс называется разворачиванием стека.
Важная особенность разворачивания стека состоит в том, что на каждом его этапе все объекты, которые выходят из области видимости, уничтожаются так же, как если бы функция выполнила команду return . Это оберегает программу от потери ресурсов и "праздно шатающихся" неуничтоженных объектов.
Когда необходимый блок try найден, программа ищет первый блок catch ( который должен находиться сразу за закрывающей скобкой блока try ). Если тип сгенерированного объекта совпадает с типом аргумента, указанным в блоке catch , управление передаётся этому блоку; если же нет, проверяется следующий блок catch . Если в результате подходящий блок не найден, программа продолжает поиск уровнем выше, пока не будет обнаружен необходимый блок catch . Если искомый блок не обнаружен, программа аварийно завершается. Рассмотрим приведённый ниже пример.
/* CascadingException — при компиляции данная программа */
/* может вызвать предупреждения о */
/* том, что переменные f, i и pMsg */
/* не используются */
#include
#include
#include
#include
Читать дальшеИнтервал:
Закладка: