Программирование >>  Разработка устойчивых систем 

1 ... 5 6 7 [ 8 ] 9 10 11 ... 196


Спецификации исключений

Вообще говоря, вы не обязаны сообщать пользователям вашей функции, какие исключения она может запускать. Однако такое поведение считается нецивилизованным - оно означает, что пользователи не будут знать, как написать код перехвата потенциальных исключений. При наличии исходных текстов они смогут просмотреть их и поискать команды throw, однако библиотеки не всегда поставляются с исходными текстами. Хорошая документация поможет решить проблемы, но много ли найдется хорошо документированных программных проектов? Специальный синтаксис С++ позволяет сообщить пользователю, какие исключения запускаются данной функцией, чтобы он мог обработать их. Речь идет о необязательной спецификации исключений, указываемой в объявлении функции после списка аргументов.

Спецификация исключений состоит из ключевого слова throw, за которым в круглых скобках перечисляются типы всех потенциальных исключений, которые могут запускаться данной функцией. Объявление функции может выглядеть примерно так:

void fO throwCtoobig, toosmall. divzero):

В отличие от этого объявления традиционное объявление функции означает, что функция может запускать исключения любых типов: void fO:

Однако следующая конструкция говорит о том, что функция не может запускать никаких исключений (проследите за тем, чтобы функции, находящиеся на очередном уровне в цепочке вызовов, не передавали исключения наверх!):

void fO throwO:

Если хороший стиль программирования, полнота документации и удобства работы с функцией вам не безразличны, обязательно включайте спецификации исключений в те функции, которые их запускают (впрочем, эта рекомендация будет обсуждаться далее в этой главе).

Функция unexpectedO

Итак, в спецификации перечисляются исключения, которые могут запускаться функцией. Но что произойдет, если функция запустит исключение, отсутствующее в списке? В этом случае вызывается специальная функция unexpected(), которая по умолчанию вызывает функцию terminate(), упоминавшуюся ранее.

А здесь перечислены классы исключений, производные от runtime error.

runt1me error

Сообщает о нарушении постусловия.

overf1ow error

Сообщает о возникновении математического переполнения.

bacl alloc

Сообщает о неудачной попытке выделения памяти.



int main() { set unexpected(my unexpected); (возвращаемое значение игнорируется) for(int i = 1; i <=3; i++) try {

f(i); } catch(Up) {

cout Up caught endl: } catch(Fit) { cout Fit caught endl:

} III:-

Классы Up и Fit предназначены только для запуска в качестве исключений. Обычно классы исключений имеют небольшие размеры, но конечно, они могут содержать дополнительную информацию, которую могут запрашивать обработчики исключений.

Функция f() в своей спецификации исключений обещает запускать исключения только типов Up и Fit. Судя по определению функции, это действительно так -

Функция set unexpected()

По аналогии с terminate() механизм вызова unexpected() позволяет вам назначить собственную функцию для обработки непредвиденных ис1С71ючений. Задача решается при помощи функции set unexpected(). Этой функции (как и set terminate()) передается адрес функции без аргументов, возвращающей void. Функция set unexpected() возвращает предыдущее значение указателя unexpected() для последующего восстановления. Чтобы использовать функцию set unexpected(), необходимо включить в программу заголовочный файл <exception>. Простейшее применение функции set unexpected() продемонстрировано в следующем примере:

: С01:Unexpected.срр

Спецификации исключений и unexpectedO

{-msc} (ненормальное завершение)

#include <except1on>

#1nclude <iostream>

using namespace std:

class Up {}: class Fit {}: void gO:

void f(int i) throw (Up, Fit) { switch(i) { case 1: throw UpO: case 2: throw FitO:

void gO {} Версия 1

void go { throw 47: } Версия 2

void my unexpected() { cout unexpected exception thrown endl; exit(O):



первая версия д(), вызываемая из f(), не запускает никаких нсключени?!, поэтому обещание выполняется. Но если кто-нибудь изменит функцию д() так, что она будет запускать исключения другого типа (например, вторая версия в нащем примере запускает исключение int), спецификация исключени!! f() будет нарушена.

В соответствии с критериями пользовательских функци11 unexpected(), функция my unexpected() не имеет аргументов и возвраи1аемого значения. Она просто выводит сообщение о своем вызове, а затем завершает программу (команда exit(O) используется для того, чтобы при построении примеров книги процесс make не завершался аварийно). Новая функция unexpectedO не может содержать команды return.

В функции main() блок try заключен в цикл for, чтобы продемонстрировать все возможные варианты обработки исключений. Так обеспечивается некое подобие восстановления: блок try выполняется в цикле for, while или do, вы перехватываете все исключения и пробуете решить проблему, а затем снова пытаетесь выполнить блок try.

Перехватываются только исключения Up и Fit, потому что создатель f() обещает, что функция запускает только эти исключения. Вторая версия д() приводит к вызову my unexpected(), так как f() в этом случае запускает исключение типа int.

Хотя значение, возвращаемое при вызове set unexpected(), проигнорировано, его также можно сохранить в указателе на функцию и восстановить позднее, как это было сделано в примере set terminate() ранее в этой главе.

Типичный обработчик unexpected сохраняет информацию об ошибке и завершает программу вызовом exit(). Впрочем, он также может запустить другое (или перезапустить текущее) исключение, либо вызвать функцию abort(). Если обработчик запустит исключение типа, входящего в спецификацию, то дальнейший поиск продолжается с точки вызова функции с данной спецификацией исключений (такое поведение характерно только для unexpected()).

Если исключение, запущенное из обработчика unexpected, недопустимо по исходной спецификации, возможен один из двух вариантов действий.

Если в спецификации ис1С71ючений функции присутствует объект std::bad ex-ception, то исключение, запущенное из обработчика unexpected, заменяется объектом std::bad exception, после чего поиск продолжается.

Если в исходной спецификации нет объекта std::bad exception, вызывается функция terminateO.

Следующая программа поясняет сказанное:

: C0l:BadExcept1on.cpp {-Ьог}

#include <exception> Для std::bad exception

#include <iostream>

#include <cstdio>

using namespace std:

Классы исключений: class A {}; class В {}:

Обработчик terminateO void my thandler() {

cout terminate calledVn :

exit(O):



1 ... 5 6 7 [ 8 ] 9 10 11 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика