Язык программирования Си++ (1119468), страница 9
Текст из файла (страница 9)
*/}}182Пространства именования• Пространство std используется для группированияфункций стандартной библиотеки:printf (“Привет\n”);// ОШИБКА, нет глобальной printf ()std::printf (“Привет\n”); // правильно• Средства стандартной библиотеки доступны черезстандартные заголовочные файлы, например,функция printf () доступна после выполнения вставки:#include <cstdio>• Для работы с именами библиотечных функций,рекомендуется использовать директивуusing namespace std;183Ошибки в программныхпродуктах• Ошибки, обнаруживаемые компиляторами (или другимикомпонентами системы программирования)Ошибки в записи лексем (55Ident)Нарушение баланса скобок в арифметических выраженияхИспользование в операторах операндов с неподходящими типамиБесконечная рекурсияИспользование одной функции там, где следует вызывать другую• Ошибки, обнаруживаемые при исполнении программ Ошибки в программах, не обнаруживаемые компонентами системпрограммирования Ошибки в данных, поступающих в программу Ошибки и сбои в работе аппаратного обеспечения184Типовы́е реакции на ошибки вовремя исполнения программы• Прекращение выполнения программы (например, вызовомсистемной функции exit ())• Возврат в вызвавшую функцию значения “ошибка” и/илиустановка специального признака (например, ненулевогозначения глобальной переменной errno)• Возврат в вызвавшую функцию какого-либо допустимогозначения и продолжение работы• Вызов специальной функции для обработки ошибочнойситуации, которая реализует те же три первых вида реакции наошибку• Выдача диагностических сообщений, затем – продолжение поодному из ранее упомянутых решений185Исключительные ситуации вязыке Си++• Функция, обнаружившая проблему, генерируетисключительную ситуацию («исключение»),чтобы передать решение проблемы тойфункции, которая её вызвала (непосредственноили опосредованно)• Функция, которая готова решать данныепроблемы, заранее указывает, что будетперехватывать такие исключения186Исключительные ситуации вязыке Си++• Фиксация ошибочной ситуации отделена от обработки• Этапы управления исключительными ситуациями:1.
Выделение блока программы, в котором возможновозникновение исключительной ситуации и длякоторого организован перехват этой ситуации2. Фиксация исключительной ситуации и передачауправления обработчику3. Обработка исключительной ситуацииобработчиком187Исключительные ситуации вязыке Си++• try-блок– блок, в котором возможновозникновение исключительной ситуации• catch-блок – блок обработки исключения• throw– оператор возбуждения исключенияvoid f (){ /* ...
*/try{ /* ... */ throw Exception ();}catch (Handle) { /* ... */ }}trythrowcatch (Handle1)catch (Handle2)catch (Handle3)188Переопределение операциииндексации в классе срокchar & string::operator [] (int i) // С остановкой работы{ if (i < 0 || i >= size) { cerr << “ошибка:” << i << endl; exit (1); }return p [i];}char & string::operator [] (int i) // С возбуждением исключения{ if (i < 0)throw “string: задан отрицательный размер”;if (i >= size) throw i;// слишком большой размерreturn p [i];}void g (int i) { /*...*/ try { string a (i), b (7); b [i] = a [i – 1]; /*...*/ }catch (int n) { /* ... */ }catch (const char * diagn) { /* ...
*/ } }189Исключительные ситуации вязыке Си++• Некоторый обработчик catch (Handle) будет вызван:1. Если тип Handle имеет тот же тип, что и Exception2. Если тип Handle является однозначным доступным базовымтипом для типа Exception3. Если Handle и Exception являются указателями, и условия 1)или 2) выполняются для типов, на которые они ссылаются4. Если Handle является ссылкой, и условия 1) или 2)выполняются для типа, на который ссылается Handle• Любой указатель совместим со свободным указателем:перехватчик catch (void*) пригоден для обработки любогоуказателя, не перехваченного предыдущими перехватчиками190Действия при возбужденииисключенияclass X { /* ... */ public: X (char, double); X (const X&);~ X ();/* ...
*/ };void f (double y) { /* ... */ X z (‘+’, y);throw z; /* ... */ }main ()/* ... */{ /* ... */ try { /* ... */catch (X) {}f (1.2);/* ... */ }/* ... */ }• Шаг 1. При выходе из функции f () из-за возбужденияисключительной ситуации, создаётся временный объект(копия объекта z), с которым работает обработчик• Копия существует всё время до тех пор, пока исключениене будет обработано (произойдёт выход из catch-блока)Действия при возбужденииисключения• Шаг 2.
Выполняется “свёртка стека”: для объектовtry-блока это эквивалентно выходу из блока спомощью оператора goto• Конструктор копирования для типа X и всенеобходимые деструкторы должны быть доступны вточке возбуждения исключения• Внутри обработчика исключения само это исключениеможно возбудить повторно: внутри обработчика (либовнутри функции, вызываемой из обработчика) можновставить оператор throw без параметров192Действия при возбужденииисключения• Шаг 3. При возбуждении исключения (выполненииоператора throw с параметром) в спискеобработчиков объемлющего блока ищется нужныйобработчик (статическая ловушка)• Если подходящий перехватчик найден, выполняетсяего составной оператор (тело перехватчика), затемуправление передаётся оператору, расположенномуследом за последним перехватчиком той группыперехватчиков, в которую входит сработавшийперехватчик193Действия при возбужденииисключения• Шаг 4. Если нет подходящего перехватчика,осуществляется выход в объемлющий блок• Далее выполняется свёртка стека с чередованиемстатических и динамических ловушекint main () {try {f ();}catch (int) {catch (float) {}/* ...
*//* ... *//* ... */ }/* ... */ }void f () {try {g ();}catch (float) {catch (char) {}/* ... *//* ... *//* ... */ }/* ... */ }void g () {/* ... */try { double d = 1.0;throw d;}catch (int) { /* ... */ }catch (long) { /* ... */ }}194Действия при возбужденииисключения• Шаг 5. Если ни один обработчик вплоть до функцииmain () не перехватил возбуждённое исключение,работа программы прекращается: вызываетсяфункция завершения работы terminate ()• Работа функции terminate () по умолчанию состоит ввызове системной функции остановки abort (), но еёможно подменить, обратившись заранее с нужнымпараметром к функции set_terminate ():typedef void (* pf) ();pf set_terminate (pf); // возвращается предыдущая функцияВызов функции terminate ()• Функция terminate () вызывается:1. Если в программе нет подходящего обработчикавозбуждённого исключения2.
Если делается попытка повторно возбудить исключение(выполняется оператор throw без параметра), а активногоисключения нет (то есть перевозбуждение происходит не вперехватчике и не в вызванной из него функции)3. Если деструктор, вызванный в процессе свёртки стека, сампытается завершить свою работу, возбуждаяисключительную ситуацию4. Если система не в состоянии справиться со свёрткой стека(стек разрушен)196Исключительные ситуации•В программе можно организовать перехват вообще всех исключительныхситуаций, которые могут в ней возникнуть, использование синтаксическойконструкции “эллипс” (catch (...)) означает присутствие любого аргумента(шаг 1 не выполняется, копирования объекта-исключения не происходит):void f (){ /*...*/ try { /*...*/} // Основная работа f ()catch (...)// Перехват “всех остальных ситуаций”{ /*...*/} } // Обработка исключений•С try-блоком можно связать несколько блоков обработчиков исключений•При поиске подходящего обработчика они просматриваются в томтекстуальном порядке, в котором записаны в программеПерехват производных типов должен предшествовать перехвату базовогоПерехват “всех остальных исключений” с помощью эллиптическойконструкции catch (...) должен всегда находиться в списке обработчиковпоследним197••Исключительные ситуации•В обработчике исключения в качестве параметра перехвата можноуказывать не только тип, но и имя формального параметра исключения,имеющего перехватываемый тип (это приведёт к повторному копированиюобъекта-исключения с возможным преобразованием типа от производногок базовому):char lex () { char c; /*...*/ if (c < 21) { /*…*/ throw c;} /*…*/ return c; }try { char m = lex (); /* ...
*/ }catch (char c){ cout << “неверный символ ” << c << endl; }или catch (char &c) { cout << “ссылка на плохой символ ” << c << endl; }•К типу, используемому для перехвата исключения, можно добавитьспецификатор const, запрещая модификацию параметра в перехватчике•Указание в заголовке обработчика ссылочного типа блокирует повторноекопирование. В этом случае возможно изменение (c += ‘0’) значенияисходного объекта-исключения, точнее его первой копии, которое можетбыть заметно при выполнении оператора throw без параметров.198Исключительные ситуации•••Ошибки разных типов можно разделить между исключениями сразличными именами, передавая их обработку разным обработчикам:struct Except { int i; Except (int k) { i = k; }}; /* ... */try { /* ...