|
Программирование >> Структура ядра и системные вызовы
Если после выполнения блока-ловушки программа не завершается, управление передается оператору, следующему за ловушками. В приведенном выше примере компиляция и пробный запуск программы без исключительных ситуаций дали следующие результаты: % СС simple exception.с % a.out hello 1: hello Finish a.out Если перезапустить эту программу без указания какого-либо аргумента, то возникнет исключительная ситуация и программа вьщаст такие результаты: % a.out exception: Insufficient no. of argument main: continue here after exception В качестве аргумента в операторе throw можно указывать и имя объекта класса. Это позволяет оператору throw передавать в блок-ловушку больше информации, что расширяет возможности диагностики ошибок и уведомлений о них. Приведенная ниже программа - это переработанный вариант предыдущего примера: source module: simple2.C ♦include <iostream.h> class errObj { public: int line; char* msg; I errObj( int lineNo, char* str ) line = lineNo; msg = str; -errObj0 {); main{ int argc, char* argv[J) ( if (argc==l) throw errOfcj ( LI№ ,*insufficient no. of arguments ); while (--argc > 0} cout argc : argv[argc] endl; cout Finish << argv{01 endl; return 0; .h catch (errObj& obj ) cerr exception at line: cSsj.line , msg: obj .msg endl; cout main: continue here after exception\n ,K-return 1; Компиляция и пробный запуск этой программы с исключительной ситуацией дали следующие результаты: % СС simple2.C % a.out exception at line: 23, msg: Insufficient no. of arguments main: continue here after exception , Если исключительная ситуация генерирована, но ни один из блоков-ловушек в этой же функции не соответствует аргументу оператора throw, то функция возвращается в вызвавшую ее функцию (или функции) и на соответствие аргументу оператора throw проверяются блоки-ловушки в каждой из этих функций. Данный процесс прекращается в том случае, если обнаружен соответствующий блок-ловушка и выполнение программы продолжается в этом блоке и следующем за ним фрагменте кода либо если соответствия нет и вызывается встроенная функция terminate. Функция terminate, в свою очередь, вызывает функцию abort, которая прерывает программу. Когда функция возвращается в вызвавшую ее функцию (или функции) вследствие выполнения оператора throw, все объекты, локальные для завершившей работу функции, освобождаются через свои деструкторы, и область динамического стека, зарезервированного для этой функции, также освобождается. Эту концепцию иллюстрирует следующий пример: source module: simple3.C ♦include <iostream.h> void f2 ( int X ) try { switch (X) ( case 1: throw exception from f 2 case 2: throw 2; . cout << f2: got x arguments.\n ; return; catch (int no arg ) { cerr f2 error: need at least no arg arguments\n ; cerr f2 returns after an exceptionXn ; main{ int argc, char* argv[]) try { f2(argc); cout main: f2 returns normally\n ; return 0; catch (const char* str ) { cerr main: << str endl; cerr main: f2 returns via an exeception\n ; return 1; Если программа вызывается без аргументов, то функция /2 выполняет оператор throw exception from f2\ что инициирует выполнение блока catch (const char* str) в функции main. Программа дает следующие результаты: % СС simpleS.C % а.out main: exception from f2 main: f2 returns via an exeception Если же программа вызывается с одним аргументом (и значение argv равно 2), то в функции f2 выполняется оператор throw 2, что инициирует выполнение блока catch (int no arg) в функции/2. Результаты программы: % а.out hello f2 error: need at least 2 arguments f2 returns after an exception , main: f2 returns normally Наконец, если программа вызывается с двумя и более аргументами, то/2 не создает исключительной ситуации, а результаты выполнения программы будут таковыми: % а.out hello world f2 : got 3 arguments, main: f2 returns normally 2.12.1. Исключительные ситуации и соответствие им блоков-ловушек Когда выполняется оператор throw с аргументом типа Т, то при выборе блока-ловушки для перехвата исключительной ситуации руководствуются определенными правилами. В частности, если тип данных блока-ловушки - С, то блок-ловушка выполняется при соблюдении любого из следующих условий: Тип Т совпадает с типом С; . Г - это тот же тип данных, что и С, но один из них определен с помощью ключевого слова const или volatile; С является ссылкой на Т или наоборот; С - это открытый или защищенный базовый класс для Т, Г И С - указатели. Т можно преобразовать в С путем стандартного преобразования указателей. 2.12.2. Объявление функций с оператором throw В объявлении функции при необходимости можно задать набор исключительных ситуаций, которые она будет прямо или косвенно генерировать. Этот набор вводится в виде списка генерации (throw list). Например, следующий оператор объявляет внешнюю функцию fund, которая может генерировать исключительные ситуации с данными типа const char* или int. extern void funct (char* ar) throw(const char*, int); Список генерации может быть пустым. Это значит, что функция не будет генерировать никаких исключительных ситуаций. Приведенный ниже оператор объявляет функцию funct2, которая не будет возбуждать никаких исключительных ситуаций ни прямо, ни косвенно: extern void funct2(char* ar) throw(); Если же функция/wAic/2 все-таки вызовет оператор throw, то будет вызвана встроенная функция unexpected. По умолчанию эта функция вызывает функцию abort, которая прерывает программу. Список генерации не является частью объявления функции, следовательно, он не может использоваться для перегрузки функций. Например, компилятор С++ считает следующие два объявления функций одинаковыми: extern void funct3(char* ar) throw(char*); extern void funct3(char* ar=0); 2.12.3. Функции terminate и unexpected Функция terminate вызывается в том случае, если оператор throw выполняется, но соответствующий блок-ловушка не обнаруживается. По умолчанию эта функция вызывает функцию abort, которая прерывает программу. С помощью функции setjerminate пользователи могут инсталлировать в terminate вместо abort свои функции: extern void user terminate( void ); void (*old handler) (void) ; old handler = set terminate( user reminate ); В этом примере user terminate - определенная пользователем функция, которая должна вызываться при активизации terminate. Функция userjermi-nate инсталлируется посредством функции setjerminate, а старая функция, инсталлированная в функции terminate, сохраргяется в переменной old handler Функция unexpected вызывается в том случае, если оператор throw выполняется в функции, которая объявлена с пустым списком генерации. По умолчанию функция unexpected вызывает функцию terminate, которая прерывает работу программы. С помощью функции setunexpected пользователи могут инсталлировать в unexpected вместо terminate свои функции: extern void user unexpected( void ); void (*old handler)(void); old handler = set unexpected( user unexpected ); В данном примере userunexpected - определенная пользователем функция, которая должна вызываться при активизации функции unexpected. Функция userjunexpected инсталлируется посредством функции setunex-pected, а старая функция, инсталлированная в функции unexpected, сохраняется в переменной oldjiandler. Поскольку предполагается, что функции terminate и unexpected никогда не выполняют возврат в вызывающие их функции, то все инсталлируемые пользователем функции, которые будут вызываться функциями terminate или unexpected, заканчиваясь, должны завершать и саму программу. В хорошо продуманной программе функции terminate и unexpected должны вызываться редко, поскольку их применение говорит о том, что в пользовательских программах не учтены все возможные исключительные ситуации, т.е. о недостаточно высоком уровне программирования. Единственным исключением является использование библиотек С++ третьих фирм, когда генерируются не указанные в документации исключительные ситуации. В этом случае пользователи должны сообщать о возникших проблемах своим поставщикам и инсталлировать программы-обработчики функций terminate и (или) unexpected лишь в качестве временной меры. 2.13. Заключение В этой главе рассматриваются принципы объектно-ориентированного программирования и свойства языка С++, соответствующего проекту стандарта ANSI/ISO. Отмечается, что С++ построен на базе языка С с добавлением конструкций, поддерживающих объектно-ориентированную технологию программирования. К таким конструкциям относятся объявление классов, наследование классов, полиморфизм на базе виртуальных функций, шаблоны функций и классов. Кроме того, рассматривается принятый в С++ метод обработки исключительных ситуаций. Практическое использование новых конструкций иллюстрируется на обширных примерах. Изложенный здесь материал поможет пользователю систематизировать имеющиеся знания о методах программирования на языке С++, разобраться в информации, представленной в остальных главах книги. Возможно, некоторые читатели и не знакомы с новыми возможностями ANSI/ISO С++, которые описаны в этой главе достаточно подробно. Глава 3 дает представление о библиотеках потоков ввода-вывода С++, которые интенсивно используются всеми приложениями, написанными на С++, поможет читателям изу1шть некоторые особенности их применения. 2.14. Литература 1. Andrew Koenig, Working Paper for Draft Proposed International Standard for Information Systems - Programming Language С++ (Committees- WG21/ N0414, X3J16/94-0025), January 1994. 2. Margaret A. Ellis, and Bjarne Stroustrup, The Annotated C+ + Reference Manual Addtson-Wesley, 1990. 3. Bjarne Stroustrup, The С++ Programming Language, Addison Wesley, 1991.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |