Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 52
Текст из файла (страница 52)
Например, Ьугот Еггог Зуп1ах еггог )" ожидалось первичное выражение' ); О.- саяе Еехет: РЛт, ~У )дои6!е д=рт1т )1гие)) ! 1.е11 !'= д, Ьгеаб, ) 1НтотЕттот Хего д1осде )), Теперь можно определить драйвер, который обрабатывает псключения Хего с!1о!с)е и Буп1ох еггог. Например: !п1 та!а )ш1 агут, сбаг* агуо))) ( тЫ!е )'три» ! 1гу ) передает обработ тику объект Яуп1ах еггог, содержащий указатель на строку "ожидалось первичное выражение".
Сообщение о делении на ноль не требует передачи данных: доиЬ!е Ра жег 1етт )Ьоо! уе» /т' улножение и делетте ! 236 Глава 8. Пространства имен и исключения Лехег де! !ойеп (); () !Еехег.сиге 1ой== йехегЕХ0~ Ьгеай; (Г' !).ехег сиге !ой == З.ехег,РК!Ы"с) сопипие; сои! «Рагяегсехрг фа1зе) « '~р'; са!сй (Еггог:Хето й!ок)е) ( сетт « 'попьипка деления на кольер'; 11 (Еехегссигг !ой м Еехет:РКРЩ яй!р (); са!сй (Еггог;Буп!ох етгот е) ( сегг « "синтпакси песков ошибка: ' «е.р « '~п; Ц (Еехег сиге !ой м Еехет;РК1йт1) зй!р (); (г'(!при!1=йс!и) де1е!е !при!; ге!итп по о1 еггогя, Бо всех случаях, кроме ошибки, произошедшей в конце выражения, ограниченного лексемой РЮНТ (т.
е. концом строки или точкой с запятой) гпат () вызывает функцию восстановления яй(р (). Функция яй(р () пытается привести синтаксический анализатор в нормальное состояние после ошибки, пропуская лексемы до тех пор, пока не встретит конец строки нли точку с запятой, Функции яй(р () и !при! являются очевиднымп кандидатами на вк.почение в пространгтво имен Рг(пег. патпезрасе 11г(оег ( зЫт 1я!геат' !при!; оо(дей(р (), ) по(д Вг1оегг зй1р () шй11е ('1прий ( сйаг сй, !при!- уе! (сй); яш!!сй (сй) ( сазе о~по сазе ','. ге!игп; ) ) Код для функции яй1р () намеренно написан на более низком уровне абстракции, чем синтаксический анализатор, Это сделано для того, чтобы во время обработки исключений синтаксического анализатора не быть прерванным новыми исключениями от синтаксического анализатора.
Я сохранил подсчет числа ошибок н возврат зтого числа из программы. Не бесполезно знать, встречались ли ошибки во время выполнения программы, даже если она смогла восстановиться после них. 237 8.3. Исключения Я не поместил тат () в пространство Рпоег. Глобальное имя тасп () является «точкой отсчета» программы Г3 3.2); тасп () в отдельном пространстве имен не имеет особого смысла.
В программе реального размера большая часть кода из спа!п () переместится в отдельную функцию в пространстве имен Рг(нег. 8.3.3.1. Альтернативные стратегии обработки ошибок Исходный код обработки ошибок был короче и элегантней, чем версия с использованием исключений. Однако, эта элегантность достигалась тесной зависимостью между частями программы. Такой подход плохо масштабируется при переходе к программам, составляемым из независимо разработанных библиотек. Мы могли оы рассмотреть нариант отказа от отдельной функции обработки ошибок зй1р () путем введения переменной состояния в та!и ().
Например: !п1 та1п (!п1 агдс, сваг'алто()) О пример плохого стиля ( О- 6оо1!п еггог= Еа!яе, ш6!!е ('Рг!оег:!при!) ( 1гд ( Еехег.де! !опек(), Ц' (Еехег.сигг 1оМ == Еехег:Еб!Р) Ьгеа!с; Ц' (Еехег. сигг 1оМ == Еехег..РК!И7) ( !п еггог = Га!зе, сопипие; (! (!и еггог==!а!зе) сои1 «Рагяеп,ехрг(ра!се) <с'~п', са1с6 (Еггог:Хего с!!о!с!е) ( сегг« 'попытка деления на ноль'и; и 'еггог= 1гие; ++по ор еггогга са1с6 (ЕггогсБуп1ах еггоге) ( сегг « 'синтаксическая ошибка: ' «е р « ~п"; !п еггог= 1гие; «+по ог еггогл; !7" (Рг!оег:!при1ый31с!сс!и) де!е1еРИиеглпри» ге1игпРг!оег;ло о! сггогя, Я счптак! это плохой идеей по нескольким причинам: (() Переменные состояния являются распространенным источником ошибок и путаницы, особенно если они оказывают влияние на значительные фрагменты программы. В частности, я считаю, что вариант гпа!п () с использованием 1п еггог менее читабелен, чем версия с функцией з7с1Р (). [2) Как правило, разделение кода обработки ошибок и «нормального» кода является хорошей стратегий.
Глава 8. Пространства имен и исключения 238 1п1 тагп [1п1 агус, сЬаг' асуп [)) ( итпу пот езрасе звб из! нупатезрасе 0г1оег; зтггсЬ ]исус) ( сазе 1. 1при1 = Ьс1п, Ьгеау; сазе рл // тление споро и аргументов шри1 = нет ге 1 сглаз ггеа т ]агу[1) Г ЬгеаЬ; Не/аий сегг « "слишком много аргум ентое1п"; ге1игп 1; // чтение ил стандартного ввода // то же, что и раныие Обсужление исключений продолжается в главе 14.
8.4. Советы [1] Пользуйтесь пространствами имен для выражения логической структуры; 8 8.2. [2) Помещайте все нелокальные имена, за исключением гааьп [), в пространства имен; з 8.2. [3) Проектируйте пространства имен таким образом, чтобы ими бьшо улобно пользоваться, и исключайте возможность случайного доступа к пространствзм, не имеющим отношения к вашей задаче; з 8.2 4. [4) Избегайте слишком коротких названий пространств имен; з 8.2.7.
[5] Если требуется, пользуйтесь псевдонимами для сокращения имен пространств; ~~ 8.2.7. [6) Ваши пространства имен не лолжны усложнять жизнь пх пользователей (в частности, нз-за сложностей с обозначениями); 9 8.2.2, 9 8.2.3. [7) Пользуйтесь формой МатезрасестетЬег прн опрелелении членов пространств имен; з 8,2.8. [8) Пользуйтесь формой из1пу патезрасе только для перенесения старого кода или в локальной области видимости; з 8.2.9. [3) Опасно писать обработку ошибок на том же уровне абстракции, что и код, которьш вызвал ошибку; код обработчика может повторить ту же самую ошибку, которая вызвала перелачу ем у управления. Выяснение того, как зто может произойти в варианте та(п [) с 1п егтог, я оставляю в качестве упражнения (з 8.5[7)).
[4) Требуется больше модификаций при добавлении кола обработки ошибок к «нормальномуь коду, чем при добавлении отдельных процедур обработки ошибок. Целью обработки исключений является решение нелокальных по своей природе проблем. Если проблема может быть решена локально, почти всегда так ее н следует решать. Например, нет необходимости в использовании исключений для обработки ситуации, когда передано слишком много аргументов: 239 8.5, Упражнения [9] Пользуйтесь исключениями для отделения обработки ошибок от кода, выполняющего обычные действия; 9 8.3.3. [1О] Для исключений применяйте типы, определяемые пользователем, а не встроенные типы; 9 8.3.2.
[11] Не пользуйтесь исключеннягии, когда достаточно локальных управляющих структур: 9 8.3.3.1. 8.5. Упражнения 1. (ь2.5) Напшвпте модуль, реализующий двусвязный список строк эЫпд в стиле модуля агаси из 9 2А. Поэкспериментируйте с ним, создав список названий языков программирования.
Реализуйте функцию зог1 () для этого списка н функцию, которая меняет в нем порлдок строк на протнвоположньш. 2. ('2) Возьмите какую-нибудь небольшую программу, в которой используется по крайней мере одна библиотека, но не применяются пространства имен. Моднфициру йте ее так, чтобы в ней использовалось пространство имен для этой библиотеки. Подсказка: 4 8.2.9.
3. ('2) Реализуйте программу калькулятора в виде модуля в стиле 9 2А с использованием пространств имен. Не пользуйтесь глобальнымц иэ(пд-диреюливаьчи. Запомните допущенные вами ошпооки. Предложнтс способы устранения таких ошибок в будущем. 4. (*1) Напишите программу, которая генерирует исключение в одной функции, и перехватывает его в другой. 5. (*2) Напишите программу, состоящую из функций, вызывающих друг друга до глубины вложенности вызовов, равной 10. Введите аргумент для каждой функции, который определял бы, на какой глуонне вложенности сгенерировано исключение. Пусть та(п () перехватывает эти исключения и печатает информацию о перехваченном исключении.
Не забудьте случай, котла исключение перехватывается в функции, которая его сгенерировала, 6. (*2) Измените программу из ~~ 8.5[5] таким образом, чтобы можно было измерить, отличаются ли затраты на перехват исключений в зависимости от того, где в стеке функций было сгенериронано исключешге. Добавьте строковый объект в кажлую функцию и произведите измерения снова. 7. ('1) Найщите ошибку в первой версии та(п () в 9 8.3.3.1. 8. ("2) Напишите функцию, которая либо возвращает значение, либо генерирует исключение, в зависимости от значения аргумента.
Измерьте разинцу во времени выполнения для этих случаев, 9. ("2) Перепишите версию калькулятора пз э' 8.5[3] с использованием исключений. Запомните допущенные вами ошибки. Предложите способы устранения таких ошибок в будущем. 10. (*2.5) Нашашпте функции р(из (), ттиэ (), ти(1(р!у () и йиЫе (), проверяющие возможные переполнения (в обе стороны) и генерирующие исключения при возникновении таких ошибок. 11.
(*2) Перепишите программу калькулятора с использованием функций из 9 8.5[10]. Исходные файлы и программы Форма должна следоеащь за функцией. — Яе Корбузьер Раздельная компиляция — компоновка — заголовочные файлы заголовочные файлы стандартной оиблиотеки — правило одного определения 10глк) — компоновка кода, написанного не па С+'- — компоновка и укззатели на функции — использование заголовочных файлов для выражения модульности — единственный заголовочный файл — несколько заголовочных файлов — стражи включения — программы — советы — упражнения 9.1.
Раздельная компиляция Файл является традиционной единицей хранения информации в файловой системе и не менее традиционной единицей компиляции. Супгествуют системы, которые не хранят, не компилируют и не представляют программисту программы на С-ь-ь в виде набора файлов. Тем не менее, оосуждение в атой главе сосредоточено на системах, использующих традиционные файлы.
Как правило, невозможно хранить законченную программу в одном файле. В частности, код стандартных библиотек и операционной системьг не предоставляется в виде исходных текстов в качестве части пользовательской программы. Даже хранение всего пользовательского кода в единственном файле для приложения реального размера и непрактично, и неудобно. Разбиение программы па файлы помогает подчеркнуть ее логическую структуру, облегчает ее понимание другими и позволяет компилятору обеспе*пгть зту логическую структуру.