Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 154
Текст из файла (страница 154)
Часовые Когда я писал операторы «или» для сотр1ех, я не беспокоился о связанных потоках Я 21.3.7) или о том, не приведет ли изменение состояния потока к исключению Я 21.3.б). Я считал — и правильно — что обеспеченные библиотекой функции сами позаботятся об атом за меня. Но каку Таких функций несколько десятков. Если бы нам пришлось писать замысловатый код для обработки связанных потоков, национальных особенностей Я 21.7), исключений и т. д.
в каждой из них, код мог бы стать довольно запутанным. Взятый на вооружение подход заключается в обеспечении общего кода через класс кеп1гу (часовой). Код, который должен выполняться первым 1«префвкскод>). — например, очистка связанного потока — вводится в виде конструктора кеп1гу. Код, который должен выполняться последним («суффикс-код>) — например, генерация исключений, вызванных изменением состояния, — обеспечивается через деструктор зеп1гу 1етр!аге <с1аиз СЬ, с!аяк Тг = сЬаг 1гайк<СЬ» с!акк Ьаз!с оя!геат: о!гена!риЫ!с Ьая!с !ок<СЬ, Тг> ( //," с1аяз зепггу; сетр!а1е <с!аяя СЬ, с1аяя Тг = сЬаг 1ганя<СЬ» с!аяя Ьаз!с ояггеат<СЬ, Тг>сяеп1гу ( риЫ!с екрус!1 кеп1гу (Ьак!с ок!геат<СЬ, Тг>6 к(; -зеп игу ((. орегагог Ьоо1 ((, Таким образом, общий код «выносится за скобки», и отдельные функции можно на- писать следующим образом: гетр!а!е<с!азз СЬ, с!акк Тг= сЬаг 1ганз<СЬ» Ьаз!с ок1геат<СЬ,Тг Ь Ьая!с ояггеат<СЬ, Тс>сорега1ог < (т1 !) ( яепггд я (*1!Пя(; (/ (!я(( // проверка, все ли готова для начала вивода яегягаге (/а!!Ь!1(; ге!игл *1Ь!я; ) //вывод числа ге!ига '1Ь!я; Этот прием, использующий конструкторы и деструкторы для выполнения инициирующего и заключительного кода для класса, может пригодиться во многих случаях.
Естественно, Ьая!с !з1геагп имеет похожий класс членов «часовых>. Глава 21. Потоки 692 21.4. Форматирование 21.4.1. Состояние формата Форматированием ввода/вывода управляют набор флагов и целочисленные значе- ния в соя Ьазе потока: с1аяяюв Ьазе( риЫса //-. // имена флагов формита: (урес(е/ллр1етел1аиол с(е(снес(1/т(/(ауя; я1апс сопя( (т у(ауз я(с(ршз, // пропуск символов-разделителей на входе (е/1, // выравнивание поля: отступ после значения ПОИ, // отступ перед значением 1п1егпа(, // отсп уп между знаком и значениелс Ьоо(а(рйа, // вывод сшсволического представления (псе и/айе // систелса счисления для целых чисел: десятичная // шестнадцатеричная // восьмеричная //ооозначение числа с плавающей точкой: д.дддддЕддд // дддд, сЫ с(ес, Ьех, ос1, яс(елв)сс, Яхес(, // на выходе префикс О перед восьмеричными // шслалш и Ох перед исестнидцатеричнылш // выводить незначащие нули //явный 'с-' перед положительными целыми // 'Е', 'Х' влсесто 'е', 'х' яйоисЬаяе, яйосоросл1, яйошроя, иррегсаяе, // относится к выравниванию полей (у 2 С 4 5) // относится к системе счисления (з 21.4.2) //относится к выводу чисел с плавающей точкосс (у 2 (.43) // очистки буфера после каждан операции вывода ас(/ия(йе(4 Ьазе/сеЫ, /(оа(йеЫ, илйуи/ Примеры, приведенные в 6 21.2, представляют собой то, сто ооычно называют неформатированным выводом.
То есть объект превращался в последовательность символов в соответствии с некоторыми правиламн по умолчанию. Часто программисту нужно более детализированное управление. Например, необходимо управлять объемом памяти, выделенным под операции вывода, и форматом вывода чисел. Подобным образом нужно в явном виде управлять и некоторыми аспектами ввода. Управление форматированием ввода/вывода производится классом Ьаз(с (оз и его базовым классом гоз Ьаяе.
Например, класс Ьая(с (оз содержит информацию о системе счисления (восьмеричная, десятичная или шестнадцатеричная) при записи и чтении целых чисел, о точности записываемых и считываемых чисел с плавающей точкой и т. и. Он также содержит функции для установки и проверки этих управляющих переменных для каждого потока Класс Ьаз(с (оз — зто базовый класс для Ьаз(с (з(геат и Ьазсс оя1геат, так что управление форматом осуществляется епо-поточно» (для каждого потока). 693 21.4. Форматирование ~тг/(ауя/(адя () сопя!; // длл чтения флагов /т(/(ауя/(аук (/тс/)аук/); //для установки флагов ,~тг/)пук зев(/тУ(аук/) ( ге!ига/(аук 3ауя з (/); ) //добавление флага //сброс и установкафлагов тазу Яву! ауя кеЯ~т у) ауяЯ/ту(аук таяЬ) ( ее!игл/(ауя ((/(аук ()$-таку (фйтаяя)), ) ооЫ инке!/(Гт!Яауя тая)г)(гаук (/(адя ()! -таку); ) // сброс флагов //... Значения флагов определяются при реализации.
Используйте исключительно символические имена, а це специфические численные значения, даже если на сегодня в вашей реализации они вам известны. Определение интерфейса в виде набора флагов и предоставление операций для их установки и сброса проверены временем, хотя это и выглядит несколько старомод ным приемом. Главное достоинство этого метода в том, что пользователь может объединять опции. Например: сопя!йоя ЬаяеГте/)пакту ор! =!оя баке:.ЬЯюк Ьакесосс(юя Ьаяе Яхед; Это позволяет нам при необходимости произвольно устанавливать опции.
Например: оо!с(уоиг/ипсг(оп (!ок баке:Хт у) аук ор!) ( юв Ьаке: /ташауз о(с! орг(опк = сои!Яауя (ор!); //сохранение старых // опций и установки новых //... сои!/(ауя (оЫ орпопя); // восстановление опций во(й ту Гипспоп () уоиг Гипс!гоп (ту орф //-. ) ФункцияЯауз () возвращает прежний набор опций. Имея возможность читать и задавать опции, мы можем устанавливать отдельные флаги, Например: туояггеатЯауя (тупя!геатЯауя ()) !оз Ьаяескбояороз); В результате туоз! еат будет выдавать явный + перед положительными числами, а остальные опции останутся без изменений.
Старые опции считываются, и в набор при помощи логического ИЛИ добавляется яйоторок. Функция ке(/'() именно это и делает, так что пример можно переписать следующим образом: туоясгеат.яе(/(гоя баке..ябосероя) После установки флаг сохраняет свое состояние, пока не будет сброшен.
Управление опциями ввода/вывода путем явной установки и сброса флагов грубо и может привести к ошибкам. Для простых случаев более аккуратный интерфейс обеспечивают манипуляторы Я 21.4.6). Пользоваться флагами для управления состоянием потока лучше лишь с целью изучения приемов реализации, а не при проектировании интерфейса. Глава 21. Потоки 694 21.4.1.1. Копирование состояния формата Полное состояние формата потока можно скопировать функцией сору/т! (): !етр1а!в<с!аяя Сй, с1аяя Гг = сйаг !га!!и<СЬ» с1аяя Ьаис 1ои риЫ!с!ои Ьазе( риЬйс: //-.
Ьая!с !озй зарубит! (сони! Ьак!с !оийЯ; //- ); Буфер потока Я 21.6) и состояние буфера функцией сору/т! () не копируются. Однако все остальное состояние копируется, в том числе требуемые исключения (э 21.3.6) и все пользовательские добавления к состоянию Я 21.7.1). 21.4.2. Вывод целых чисел сои!.вкЯ!ок Ьаяесосг, !ов Ьаие:.Ьаверк!д); сои!.кеУ'(!оя Ьакегдес, !ои Ьаке:.ЬаиеЯк!<1); сои! кеУ (!ов Ьавксйех, !ои ЬавкьйаяеЯе!к1)„ // восьмеричные // десяти взныв //шестнадиатеричные устанавливает систему счисления без всяких побочных эффектов для остальных час- тей состояния потока. Однажды установленная, система счисления остается неиз- менной, пока не будет переустановлена.
Например, //по умолчаникв десятичная // восьмеричная сои! «1234 « ' ' «! 234 « ' '; сои!.ие(1 (гои Ьаякьосг, !ов ЬаяккЬаиере!д) сои! «!234 «' ' «1234 «' ', // шест надва)перинная сои!.ие(Г(!оя Ьаяе: йех, !ои Ьаик: ЬаяеЯе!д); сои! «1234 « ' ' «1234 « ' ', выведет 1234 1234 2322 2322 4г12 4!12. Если нам нужно сказать, какая система счисления использовалась для каждого числа, мы можем установить ийовйаве, добавив сои!иву(!оя Ьавк:жйошйаве); Тогда выведется 1234 1234 02322 02322 Ох4с(2 Ох4<12. Более изящный способ для определения системы счисления выводимых целых чисел обеспечивают стандартные манипуляторы Я 21А.6.2), Прием с добавлением новых опций логическим ИЛИ в функциях Язв () и ве(/() работает только тогда, когда какой-то харш<теристикой управляет один бит. Это не годится для таких опций, как система счисления при выводе целых чисел и вид числа с плавающей точкой.
Для подобных опций значение, определяющее вид вывода, не обязательно выражается одним битом или набором независящих друг от друга одиночных битов, Решение, примененное в <1ов!гент>, заключается в том, чтобы предоставить версию ве!/ () со вторым «псевдоаргументом», который показывает, какой вид опции мы хотим установить в добавок к новому значению. Например, 595 21.4. Форматирование 21.4.3.
Вывод чисел с плавающей точкой сонг« "по улюлчанию ~1 «1234 56789 «зл'; сои1 лег) ((оя Ьазе. зсгеп18(с, 1оз Ьаяе:ЯоаУье18~1 // научный формат соиг«научныйз3' «123456789 «зп'; сои1 зе12(1оз Ьаяе эхей, 1оя Ьазе 71 оау(е(г1); //формат с фиксированной точкой соиг«фиксированный Зр«1234 56789 «зп'; сои1зе(7(0, юя Ьазе;2(оаЯе(а), // восстановленле формата по ульол заною /1 (то есть универсального) сои1 «ло умолчанию.~т" «1234.56789 « "~л'; выведет 1234.57 1.2345678е+03 1234.567890 1234.57 ло умолчанию: научный фиксированный.
по умолчанию. По умолчанию точность — 6 цифр (для всех форматов). Точностью управляют функ- ции-члены класса (оз Ьаве: с(аяз(оя базе( риЫ(а //- зггеа те/ее ргес/зги л () салаг; з1геатзгзе ргесигоп (зггеатз1зе и), // возвращает точность // устанавливает точность 0 (а возвртлает с~ларую) О) Вызов ргес(топ () влияет на все операции ввода/вывода чисел с плавающей точкой в поток и действует до следующего обращения к ргес(з(ол (). Таким образом, соиг ргес(топ (8); соиг «1234 56789 « ' ' «1234.56789 «" «123456 «з,л'; сои1 ргесм!оп (4); соиг «123456789 « ' ' «1234.56789 « " «123456 «з и', Вывод чисел с плавающей точкой определяется форматом и точностью: Универсальный формат дает реализации самой выбирать формат представлен~ я числа в том виде, который наилучшим образом представит число в доступном пространстве.