Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 Mб
Скачать

9.1 Обработка ошибок

      Создатель библиотеки способен обнаружить динамические ошибки, но не       представляет какой в общем случае должна быть реакция на них.       Пользователь библиотеки способен написать реакцию на такие ошибки,       но не в силах их обнаружить. Если бы он мог, то сам разобрался бы       с ошибками в своей программе, и их не пришлось бы выявлять       в библиотечных функциях. Для решения этой проблемы в язык введено       понятие особой ситуации Ь.       Ь Только недавно комитетом по стандартизации С++ особые ситуации были       включены в стандарт языка, но на время написания этой книги они еще       не вошли в большинство реализаций.       Суть этого понятия в том, что функция, которая обнаружила ошибку и не       может справиться с нею, запускает особую ситуацию, рассчитывая, что       устранить проблему можно в той функции, которая прямо или опосредованно       вызывала первую. Если функция рассчитана на обработку ошибок некоторого       вида, она может указать это явно, как готовность перехватить данную       особую ситуацию.       Рассмотрим в качестве примера как для класса Vector можно       представлять и обрабатывать особые ситуации, вызванные выходом за       границу массива:       class Vector {       int* p;       int sz;       public:       class Range { }; // класс для особой ситуации       int& operator[](int i);       // ...       };       Предполагается, что объекты класса Range будут использоваться как       особые ситуации, и запускать их можно так:       int& Vector::operator[](int i)       {       if (0<=i && i<sz) return p[i];       throw Range();       }       Если в функции предусмотрена реакция на ошибку недопустимого значения       индекса, то ту часть функции, в которой эти ошибки будут перехватываться,       надо поместить в оператор try. В нем должен быть и обработчик особой       ситуации:       void f(Vector& v)       {       // ...       try {       do_something(v); // содержательная часть, работающая с v       }       catch (Vector::Range) {       // обработчик особой ситуации Vector::Range       // если do_something() завершится неудачно,       // нужно как-то среагировать на это       // сюда мы попадем только в том случае, когда       // вызов do_something() приведет к вызову Vector::operator[]()       // из-за недопустимого значения индекса       }       // ...       } Обработчиком особой ситуации называется конструкция       catch ( /* ... */ ) {       // ...       }       Ее можно использовать только сразу после блока, начинающегося служебным       словом try, или сразу после другого обработчика особой ситуации. Служебным       является и слово catch. После него идет в скобках описание, которое       используется аналогично описанию формальных параметров функции, а именно,       в нем задается тип объектов, на которые рассчитан обработчик, и,       возможно, имена параметров (см. $$9.3). Если в do_something() или в       любой вызванной из нее функции произойдет ошибка индекса (на любом       объекте Vector), то обработчик перехватит особую ситуацию и будет       выполняться часть, обрабатывающая ошибку. Например, определения следующих       функций приведут к запуску обработчика в f():       void do_something()       {       // ...       crash(v);       // ...       }       void crash(Vector& v)       {       v[v.size()+10]; // искусственно вызываем ошибку индекса       }       Процесс запуска и перехвата особой ситуации предполагает просмотр       цепочки вызовов от точки запуска особой ситуации до функции, в которой       она перехватывается. При этом восстанавливается состояние стека,       соответствующее функции, перехватившей ошибку, и при проходе по всей       цепочке вызовов для локальных объектов функций из этой цепочки вызываются       деструкторы. Подробно это описано в $$9.4.       Если при просмотре всей цепочки вызовов, начиная с запустившей       особую ситуацию функции, не обнаружится подходящий обработчик, то       программа завершается. Подробно это описано в $$9.7.       Если обработчик перехватил особую ситуацию, то она будет обрабатываться       и другие, рассчитанные на эту ситуацию, обработчики не будут       рассматриваться. Иными словами, активирован будет только тот обработчик,       который находится в самой последней вызывавшейся функции, содержащей       соответствующие обработчики. В нашем примере функция f() перехватит       Vector::Range, поэтому эту особую ситуацию нельзя перехватить ни в       какой вызывающей f() функции:       int ff(Vector& v)       {       try {       f(v); // в f() будет перехвачена Vector::Range       }       catch (Vector::Range) { // значит сюда мы никогда не попадем       // ...       }       }