straustrup2 (852740), страница 66
Текст из файла (страница 66)
Это только усложнит систему. Удачная система, обладающая устойчивостью кошибкам, должна строиться как многоуровневая. На каждом уровне надо обрабатывать настолькомного ошибок, насколько это возможно без нарушения структуры системы, оставляя обработку другихошибок более высоким уровням. Назначение terminate() поддержать такой подход, предоставляявозможность экстренного выхода из такого положения, когда нарушен сам механизм обработки особыхситуаций, или когда он используется полностью, но особая ситуация оказалась неперехваченной.Функция unexpected() предназначена для выхода из такого положения, когда не сработало основанноена описании всех особых ситуаций средство защиты.
Это средство можно представлять какбрандмауер, т.е. стену, окружающую каждую функцию, и препятствующую распространению ошибки.Попытка проводить в каждой функции полный контроль, чтобы иметь гарантию, что функция либоуспешно завершится, либо закончится неудачно, но одним из определенных и корректных способов, неможет принести успех. Причины этого могут быть различными для разных программ, но для большихпрограмм можно назвать следующие:[1]работа, которую нужно провести, чтобы гарантировать надежность каждой функции, слишкомвелика, и поэтому ее не удастся провести достаточно последовательно;[2]появятся слишком большие дополнительные расходы памяти и времени, которые будутнедопустимы для нормальной работы системы (будет тенденция неоднократно проверять наодну и ту же ошибку, а значит постоянно будут проверяться переменные с правильнымизначениями);[3]таким ограничениям не будут подчиняться функции, написанные на других языках;[4]такое понятие надежности является чисто локальным и оно настолько усложняет систему, чтостановится дополнительной нагрузкой для ее общей надежности.Однако, разбить программу на отдельные подсистемы, которые либо успешно завершаются, либозаканчиваются неудачно, но одним из определенных и корректных способов, вполне возможно, важно идаже выгодно.
Таким свойством должны обладать основные библиотеки, подсистемы или ключевыефункции. Описание особых ситуаций должно входить в интерфейсы таких библиотек или подсистем.Иногда приходится от одного стиля реакции на ошибку переходить на другой. Например, можно послевызова стандартной функции С проверять значение errno и, возможно, запускать особую ситуацию, аможно, наоборот, перехватывать особую ситуацию и устанавливать значение errno перед выходом изстандартной функции в С-программу:void callC(){errno = 0;cfunction();if (errno) throw some_exception(errno);}void fromC(){try {c_pl_pl_function();}catch (...) {errno = E_CPLPLFCTBLEWIT;255Бьерн Страуструп.Язык программирования С++}}При такой смене стилей важно быть последовательным, чтобы изменение реакции на ошибку былополным.Обработка ошибок должна быть, насколько это возможно, строго иерархической системой.
Если вфункции обнаружена динамическая ошибка, то не нужно обращаться за помощью для восстановленияили выделения ресурсов к вызывающей функции. При таких обращениях в структуре системывозникают циклические зависимости, в результате чего ее труднее понять, и возможно возникновениебесконечных циклов в процессе обработки и восстановления после ошибки.Чтобы часть программы, предназначенная для обработки ошибок была более упорядоченной, стоитприменять такие упрощающие дело приемы, как "запрос ресурсов путем инициализации", и исходить изтаких упрощающих дело допущений, что "особые ситуации являются ошибками".9.9 Упражнения1.(*2) Обобщите класс STC до шаблона типа, который позволяет хранить и устанавливать функцииразных типов.2.(*3) Дополните класс CheckedPtrToT из $$7.10 до шаблона типа, в котором особые ситуациисигнализируют о динамических ошибках.3.(*3) Напишите функцию find для поиска в бинарном дереве узлов по значению поля типа char*.
Еслинайден узел с полем, имеющим значение "hello", она должна возвращать указатель на него. Дляобозначения неудачного поиска используйте особую ситуацию.4.(*1) Определите класс Int, совпадающий во всем со встроенным типом int за исключением того, чтовместо переполнения или потери значимости в этом классе запускаются особые ситуации.Подсказка: см. $$9.3.2.5.(*2) Перенесите из стандартного интерфейса С в вашу операционную систему основные операции сфайлами: открытие, закрытие, чтение и запись.
Реализуйте их как функции на С++ с тем женазначением, что и функций на С, но в случае ошибок запускайте особые ситуации.6.(*1) Напишите полное определение шаблона типа Vector с особыми ситуациями Range и Size.Подсказка: см. $$9.3.7.(*1) Напишите цикл для вычисления суммы элементов вектора, определенного в упражнении 6,причем не проверяйте размер вектора. Почему это плохое решение?8.(*2.5) Допустим класс Exception используется как базовый для всех классов, задающих особыеситуации. Каков должен быть его вид? Какая от него могла быть польза? Какие неудобства можетвызвать требование обязательного использования этого класса?9.(*2) Напишите класс или шаблон типа, который поможет реализовать обратный вызов.10. (*2) Напишите класс Lock (замок) для какой-нибудь системы, допускающей параллельноевыполнение.11. (*1) Пусть определена функцияint main() { /* ...
*/ }Измените ее так, чтобы в ней перехватывались все особые ситуации, преобразовывались всообщения об ошибке и вызов abort(). Подсказка: в функции fromC() из $$9.8 учтены не все случаи.256Бьерн Страуструп.Язык программирования С++ГЛАВА 10. ПОТОКИ"Доступно только то, что видимо"Б.
КерниганВ языке С++ нет средств для ввода-вывода. Их и не нужно, поскольку такие средства можно просто иэлегантно создать на самом языке. Описанная здесь библиотека потокового ввода-вывода реализуетстрогий типовой и вместе с тем гибкий и эффективный способ символьного ввода и вывода целых,вещественных чисел и символьных строк, а также является базой для расширения, рассчитанного наработу с пользовательскими типами данных. Пользовательский интерфейс библиотеки находится вфайле <iostream.h>.
Эта глава посвящена самой потоковой библиотеке, некоторым способам работы сней и определенным приемам реализации библиотеки.10.1 ВВЕДЕНИЕШироко известна трудность задачи проектирования и реализации стандартных средств ввода-выводадля языков программирования. Традиционно средства ввода-вывода были рассчитаны исключительнона небольшое число встроенных типов данных. Однако, в нетривиальных программах на С++ естьмного пользовательских типов данных, поэтому необходимо предоставить возможность ввода-выводазначений таких типов. Очевидно, что средства ввода-вывода должны быть простыми, удобными,надежными в использовании и, что важнее всего, адекватными.
Пока никто не нашел решения, котороеудовлетворило бы всех; поэтому необходимо дать возможность пользователю создавать иные средстваввода-вывода, а также расширять стандартные средства ввода-вывода в расчете на определенноеприменение.Цель создания С++ была в том, чтобы пользователь мог определить новые типы данных, работа скоторыми была бы столь же удобна и эффективна как и со встроенными типами. Таким образом,кажется разумным потребовать, чтобы средства ввода-вывода для С++ программировались сиспользованием возможностей С++, доступных каждому. Представленные здесь потоковые средстваввода-вывода появились в результате попытки удовлетворить этим требованиям.Основная задача потоковых средств ввода-вывода - это процесс преобразования объектовопределенного типа в последовательность символов и наоборот.
Существуют и другие схемы вводавывода, но указанная является основной, и если считать символ просто набором битов, игнорируя егоестественную связь с алфавитом, то многие схемы двоичного ввода-вывода можно свести к ней.Поэтому программистская суть задачи сводится к описанию связи между объектом определенного типаи бестиповой (что существенно) строкой.Последующие разделы описывают основные части потоковой библиотеки С++:10.2Вывод: То, что для прикладной программы представляется выводом, на самом деле являетсяпреобразованием такихобъектовкакint, char *, complex или Employee_record впоследовательность символов. Описываются средства для записи объектов встроенных ипользовательских типов данных.10.3Ввод: Описаны функции дляпользовательских типов данных.10.4Форматирование: Часто существуют определенные требования к виду вывода, например, intдолжно печататься десятичными цифрами, указатели в шестнадцатеричной записи, авещественные числа должны быть с явно заданной точностью фиксированного размера.Обсуждаются функции форматирования и определенные программистские приемы ихсоздания, в частности, манипуляторы.10.5Файлы и потоки: Каждая программа на С++ может использовать по умолчанию три потока стандартный вывод (cout), стандартный ввод (cin) и стандартный поток ошибок (cerr).
Чтобыработать с какими-либо устройствами или файлами надо создать потоки и привязать их к этимустройствам или файлам. Описывается механизм открытия и закрытия файлов и связыванияфайлов с потоками.10.6Ввод-вывод для С: обсуждается функция printf из файла <stdio.h> для С а также связь междувводасимволов,257строкизначенийвстроенныхиБьерн Страуструп.Язык программирования С++библиотекой для С и <iostream.h> для С++.Укажем, что существует много независимых реализаций потоковой библиотеки ввода-вывода и наборсредств, описанных здесь, будет только подмножеством средств, имеющихся в вашей библиотеке.Говорят, что внутри любой большой программы есть маленькая программа, которая стремитсявырваться наружу.