2.6. Использование исключенийИсключениями называют аномальные ситуации, возникающие во время исполнения
программы: невозможность открыть нужный файл или получить необходимое количество
памяти, использование выходящего за границы индекса для какого-либо массива.
Обработка такого рода исключений, как правило, плохо интегрируется в основной
алгоритм программы, и программисты вынуждены изобретать разные способы корректной
обработки исключения, стараясь в то же время не слишком усложнить программу
добавлением всевозможных проверок и дополнительных ветвей алгоритма. if ( !infile ) { string errMsg("Невозможно открыть файл: "); errMsg += fileName; throw errMsg; } Место программы, в котором исключение обрабатывается. При возбуждении исключения нормальное выполнение программы приостанавливается и управление передается обработчику исключения. Поиск нужного обработчика часто включает в себя раскрутку так называемого стека вызовов программы. После обработки исключения выполнение программы возобновляется, но не с того места, где произошло исключение, а с точки, следующей за обработчиком. Для определения обработчика исключения в С++ используется ключевое слово catch. Вот как может выглядеть обработчик для примера из предыдущего абзаца: catch (string exceptionMsg) { log_message (exceptionMsg); return false; } Каждый catch-обработчик ассоциирован с исключениями, возникающими в блоке операторов, который непосредственно предшествует обработчику и помечен ключевым словом try. Одному try-блоку могут соответствовать несколько catch-предложений, каждое из которых относится к определенному виду исключений. Приведем пример: int* stats (const int *ia, int size) { int *pstats = new int [4]; try { pstats[0] = sum_it (ia,size); pstats[1] = min_val (ia,size); pstats[2] = max_val (ia,size); } catch (string exceptionMsg) { // код обработчика } catch (const statsException &statsExcp) { // код обработчика } В данном примере в теле функции stats() три оператора заключены в try-блок, а четыре – нет. Из этих четырех операторов два способны возбудить исключения. 1) int *pstats = new int [4]; Выполнение оператора new может окончиться неудачей. Стандартная библиотека С++ предусматривает возбуждение исключения bad_alloc в случае невозможности выделить нужное количество памяти. Поскольку в примере не предусмотрен обработчик исключения bad_alloc, при его возбуждении выполнение программы закончится аварийно. 2) do_something (pstats); Мы не знаем реализации функции do_something(). Любая инструкция этой функции,
или функции, вызванной из этой функции, или функции, вызванной из функции, вызванной
этой функцией, и так далее, потенциально может возбудить исключение. Если в
реализации функции do_something и вызываемых из нее предусмотрен обработчик
такого исключения, то выполнение stats() продолжится обычным образом. Если же
такого обработчика нет, выполнение программы аварийно завершится. pstats [3] = pstats[0] / size; может привести к делению на ноль, в стандартной библиотеке не предусмотрен
такой тип исключения. throw string ("Ошибка: adump27832"); Выполнение функции sum_it() прервется, операторы, следующие в try-блоке за вызовом этой функции, также не будут выполнены, и pstats[0] не будет инициализирована. Вместо этого возбуждается исключительное состояние и исследуются два catch-обработчика. В нашем случае выполняется catch с параметром типа string: catch (string exceptionMsg) { // код обработчика } После выполнения управление будет передано инструкции, следующей за последним catch-обработчиком, относящимся к данному try-блоку. В нашем случае это pstats [3] = pstats[0] / size; (Конечно, обработчик сам может возбуждать исключения, в том числе – того же
типа. В такой ситуации будет продолжено выполнение catch-предложений, определенных
в программе, вызвавшей функцию stats().) catch (string exceptionMsg) { // код обработчика cerr << "stats(): исключение: " << exceptionMsg << endl; delete [] pstats; return 0; } В таком случае выполнение вернется в функцию, вызвавшую stats(). Будем считать,
что разработчик программы предусмотрел проверку возвращаемого функцией stats()
значения и корректную реакцию на нулевое значение. catch (...) { // обрабатывает любое исключение, // однако ему недоступен объект, переданный // в обработчик в инструкции throw } (Детально обработка исключительных ситуаций рассматривается в главах 11 и 19.) Упражнение 2.18Какие ошибочные ситуации могут возникнуть во время выполнения следующей функции: int *alloc_and_init (string file_name) { ifstream infile (file_name) int elem_cnt; infile >> elem_cnt; int *pi = allocate_array(elem_cnt); int elem; int index=0; Упражнение 2.19В предыдущем примере вызываемые функции allocate_array(), sort_array() и register_data() могут возбуждать исключения типов noMem, int и string соответственно. Перепишите функцию alloc_and_init(), вставив соответствующие блоки try и catch для обработки этих исключений. Пусть обработчики просто выводят в cerr сообщение об ошибке. Упражнение 2.20Усовершенствуйте функцию alloc_and_init() так, чтобы она сама возбуждала исключение в случае возникновения всех возможных ошибок (это могут быть исключения, относящиеся к вызываемым функциям allocate_array(), sort_array() и register_data() и какими-то еще операторами внутри функции alloc_and_init()). Пусть это исключение имеет тип string и строка, передаваемая обработчику, содержит описание ошибки. Назад ВпередСодержание |
Нет комментариев. Оставить комментарий: |