|
Программирование >> Разработка устойчивых систем
Спецификации исключений Вообще говоря, вы не обязаны сообщать пользователям вашей функции, какие исключения она может запускать. Однако такое поведение считается нецивилизованным - оно означает, что пользователи не будут знать, как написать код перехвата потенциальных исключений. При наличии исходных текстов они смогут просмотреть их и поискать команды 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):
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |