Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 159
Текст из файла (страница 159)
В реализации можно произвести доступ к этим областям следуюгцим образом: Операции ввода/вывода определяются без упоминания о типах файлов, но не со всеми устройствами можно обращаться одинаково в смысле буферизации. Например, поток оя1геат, связанный со строкой я1Ппу(ту 21.5З), нуждается не в таком типе буфера, как оя1геит, связанный с файлом Я 21.5.1). Эти трудности преодолеваются во время инициализации указанием разных типов буфера для разных потоков, Над этими типами буферов существует всего один набор операций, поэтому функции класса оя1геат не содержат кода, который бы их отличал.
Разные типы буферов являются производными от класса я1геитбцЯ Класс я1геитбиг" предоставляет виртуальные функции для операций, таких как обработка переполнения буфера сверху или снизу, в которых стратегии буферизации отличаются. Класс Ьая1с яргеатЬи/вводит два интерфейса. Открытый интерфейс предназначается главным образом для тех, кто реализует классы потоков, такие как !я1геат. оя! еат, (я1геит, я1ппдяйеат и т. д. Кроме того предоставляется защгпценный интерфейс для тех, кто реализует новые стратегии буферизации и буфера я1геатЬи/для новых источников ввода и приемников вывода. Чтобы понять, что такое я1геатби/, полезно сначала рассмотреть основополагающую модель буферной области, предоставляемую защищенным интерфейсом.
Допустим, гого яргеатЬи/имеет область записи, в которую пишет оператор «, и область чтения, из которой читает оператор». Каждая область описывается начальным указателем, текущим указателем и указателем на элемент, следующий за концом. Эти указатели доступны череа следующие функции: 713 21.6. Буферизация 1етр!а1е<с!азя СЬ, с!аяя Тг = сбаг 1гауя<СЬ» Ьаяйс я1геатби/<СЬ, Тг>; иг 1уре бак!с з1геатби/<СЬ, Тг> кяпех1с() //пропустить текущий сил~вол, зател~ ароыитать следующии ( Я1 <еургг () ург ф) ( // если в буфере есть не лленее 2-х символов убитр (1); //пропустить текущий символ те!ига Тгс!о ьа! 1уре(*ургт()); // возвращает новый текущий сил~вол ) !Т (1=-=еургг () -ургт()) ( убитр (I); ге1игп ипдегЯот () //если в буфере ровно ! сиывол // аропустить текущий символ //буфер пуст (или неаг буфера), попытка заполнить буфер: (1 (Тп:ед )н1 1уре (и/!от (), Тг. еоЯ )) ге1игп Тп,ео/() ЯО<еур1г() — дргт()) ге1игп Тгмо тг 1уре (*ур1г ()); //возвращает новый текущий символ ге1итп ипс!ет/(огв (); 1етр!аге<сIаяя СЬ, с!аяя Тт = сбит !гайя<СЬ» с!аяя Ьак!с згтеатби/( риб!!а //обычные определения 1уреде/!5 2!.2.!) о!тгиа!-Ьая!с кгтеатбиЯ1 !осаIе риб!тпЬие (сопк1 !оса1е й!ос).
//установка национальных // особенное~пей !и полуыение старых) ние на ли овальных особенностей 1оса!е уег!ос () сопз1; // получе Ьая!с зггеатби/" рибяегби/(СЬ" р, кггеатк!ге а); //унпановко палшти //для буфера //установка аозиуии (К 2!.б.!): роя Фуре рибкеебоХХ(о// 1уре оо, Ьоз ЬакесяееЫ1г твау, !оя Ьаяе: орептоде т=!оя Ьаяест(!ок Ьазесоиб; роя 1урерибзееброя(роя 1урер, соя Ьазесорептодет=гоз Ьазелт(!ок б яеыоий; !п1риЬяуас(); //исаользуеагся при синхронизаиии ввода зуас!) !К 2!.6.2) 1етрIа1е<с!акк СЬ, сIаяк Тг = сЬат 1га!1к< СЬ» баксе я!театби/<СЬ, Тг>ыгпг 1уре Ьаяк зггеатби/<СЬ, Тг>сяпех1с (); // тление следующего сгмчвола !п1 1уре ябитрс (); // продвижение ур1т() на ! !п1 гуре «уе1с (); О получение лпекуи!его символа зггеатясге яуегп (СЬ" р, яггеатз!хе п); // чтение в р(0) .р~а-!) // аоложшпь с обрааыно в буфер Доступ к буферу осуществляется через ур1г (); еур1г () отмечает границы полученной области.
Символы считываются из реального источника функциями и!лов() и ипс!ету(ого(), Вызовы 1га!1к !урез!о Ь11 1уре гарантируют, что код не зависит от фактического типа символа. Этот код допустим для различных типов буфера потока и учитывает возможность того, что виртуальные функции иТ!ою () и ипл)ег/1от () могут ввести новую область (используя зе1у ()). Открытый интерфейс к1геатби/выглядит следующим образом: Глава 21. Потоки 714 т1 1уре яипуегс (); // отлгентпь тление последнего сил~вола !п1 1уре яри1с (СЬ с); // записать с я1геаспя1ге яри1п (сопя1 СЬ" р, я!геатягге п), //записать р(0)..р (и — 1) з1геатя!ге т аоа1! (); //ввод готов? //- Открытый интерфейс содержит функции для вставки символов в буфер и извлечения их из буфера. Эти функции просты и легко встраиваются, а это имеет решающее значение для эффективности. Функции, реализующие части специфической стратегии буферизации, обращаются к соответствующим функциям защищенного интерфейса.
Например, рибяе1ЬиД) вызывает яе16иД), которая замещена в производном классе для реализации концепции этого класса по выделению памяти для буферизации символов. Использование двух функций для реализации таких операций как установка буфера яе16и7" позволяет разработчику 1оя1геат произвести некоторую «уборку» до и после польаовательской программы. Например, разработ пи< реализации может сделать оболочку вокруг вызова виртуальной функции и перехватывать исключения, сгенерированные в пользовательском коде. Но умолчанию яе16и/(0, 0) означает «отсутствие буферизации», а яе16и/ (р, и) означает использование р[0] ..р(п — 1) для хранения буферизованных символов.
Вызов гп аоа!! () используется для того, чтобы посмотреть, сколько доступных символов в буфере. Это может пригодиться, чтобы не ждать ввода. Во время считывания из потока, связанного с клавиатурой, ст.уе! (с) може~ дожидаться, пока пользователь вернется с обеда. В некоторых системах и для некоторых прикладных программ это следует учитывать, Например: Д' (с1ппйи3 ()1п аиа(! ()) ( //де! !) не заблокируеп~ с!п.уе1(с); 0 епо-то делается ) е!яе ( // уе! !) может заблокировать //делоетсл нто-то другое Отметим, что в некоторых системах трудно определить доступен ли ввод. Так, реали- зация гп ао1а1(() может (неудачно) устанавливать, что 1п алаИ() возвращает 0 в слу- чаях, когда операция ввода может пройти успешно.
В дополнение к открытому интерфейсу, используемому Ьия/с 1я1геат и оя1геат, Ьая(с я1 еатби~'предлагает защищенный интерфейс лля разработчиков буферов пото- ков. Именно там и объявляются определяющие тактику действий виртуальные функпигс 1етр1аге<с!аяя СЬ, с!аяя Уг = сдаг гга!1я<СЬ» с!аяя Ьая1с я1геатби/( рго1ес1еа'. О.- Ьая!с я1геатбиЯ о1г1иа!оо1с(!тЬие(сопзг!оса!ей!ос) //установканационольннхособенностей о1ггиа! 6ая!с я1геатби!' яе16и/(СЬ* р, яггеатяяее и); огг1иа! роя 1уре яееуо~Яо// 1уре о//, 1оя Ьаяегяееудг свау, !оя Ьаяе: орептобет = !оя Ьаяег!и(!оя Ьаяе:ои!), 715 21.6.
Буферизация о!ггиа! роя гуре кееурок (рок гуре р, !оя Ьаяесорептоде т =!ок Ьакечл )!оя Ьаяегои1), о!г1иа! !пг луп с (); //синхронизация ввода (э" 2!.б.2) тггиа! !п1 яйоготапус (); о!г1иа!к1геатк1хехяуе1п (СЬ" р, я1геатяггеп), //«тепле л символов //повторное заполнение ооло сто; возвращает пи~вол или ео/ о!г1иа! !л1 1уре иле!ег/!от (); //повторное заполнение обласлт; возвращает откол оли е% сдвигает ур! () на I и!гула! т1 1уре и/!от (); и!ггиа!!п1 1урербасу/ад(1п1 1урес=Тпео/()! //положи«пьобратно неудвлось о!гула! я1геатк!гехкри1п (сопя! СЬ'р, кпеатяуге и); // записать л символов в!ггиа! т1 1уре ооегУ!от (!л1 1уре с = Тг,еоЯ, //записать всю обласпгь К функциям ипс(еку1ош () и иЯош () обращаются для получения символа пз реального источника, когда буфер пуст, Если ввод из этого источника больше не доступен, поток устанавливается в состояние ела() Я 21.3.3). Если это не приводит к генерации исключения, возвращается 1га!1я 1дрехео/'().
После возврата символа функцией иЯош (), но не ипс/ек„-!)ош (), др1г () сдвигается на 1. Помните, что, как правило, в вашей системс больше буферов, чем введено в библиотеке сок1геат, поэтому вы можете столкнуться с задержками буферизации, даже пользуясь небуфсризованным потоком ввода/вывода, К функции ооег/1ош () обращаются для передачи символов в реальный приемник вывода по заполнении буфера. Вызов опегЯош (с) выводит содержимое буфера и символ с.
Если в данный приемник больше невозможно ничего вывести, поток устанавливается в состояние ео/(э 21.3.3). Если прн этом не сгенирируется исключение, возвращается 1ги11к 1дрехео1 (). Функция яйоштапдс () — «показать, сколько символов» («зпоч )го«««папу сйагастегк») — это дополнительная функция, позволяющая пользователю узнавать о состоянии машинной системы ввода.
Эта функция возвращает оценку, сколько символов можно считать «быстро» вЂ” скажем, очистив буфера операционной системы, а пе дожидаясь чтения с диска. Вызов яйоштапдс () возвращает -1, если функция не может обещать, ыо с пп ается хотя бы один символ без получения конца файла. Это (обязательно) — функпия низкого уровня, в больпюй степени завися!цая от реализации. Не пользуйтесь яйошталдс (), не ознакомившись внимательно с документацией на вашу систему и не проведя несколько экспериментов, По умолчанию все потоки получают глобальные национальные особенности (й 21.7). Вызов риЫтЬие (1ос) цлп !тбие (1ос) приводит к тому, что поток в качестве национальных особенностеи использует аргумен г 1ос, Буфер я1геатби/' для конкретного вида потока является производным от Ьак!с к1геатЬиб Он обеспечивает конструкторы и инициализирующие функции, которые связгявают ябгеатЬи1 с реальным источником (или приемником) символов, и замещает виртуальные функции, определяющие стратегию буферизации.