Бьерн Страуструп.
Язык программирования С++
278
основной памяти.
Например, можно воспользоваться выходным строковым потоком ostrstream для
форматирования сообщений, не подлежащих немедленной печати:
char* p = new char[message_size];
ostrstream ost(p,message_size);
do_something(arguments,ost);
display(p);
С помощью стандартных операций вывода функция do_something может писать в поток ost, передавать
ost подчиняющимся ей функциям и т.п. Контроль переполнения не нужен, поскольку ost знает свой
размер и при заполнении перейдет в
состояние, определяемое fail(). Затем
функция display может
послать сообщение в "настоящий" выходной поток. Такой прием наиболее подходит в тех случаях,
когда окончательная операция вывода предназначена для записи на более сложное устройство, чем
традиционное, ориентированное на последовательность строк, выводное устройство. Например, текст
из ost может быть помещен в фиксированную область на экране.
Аналогично, istrstream является вводным строковым потоком, читающим из последовательности
символов, заканчивающейся нулем:
void word_per_line(char v[], int sz)
/*
печатать "v" размером "sz" по одному слову в строке
*/
{
istrstream ist(v,sz); //
создать istream для v
char b2[MAX]; // длиннее самого длинного слова
while (ist>>b2) cout <
}
Завершающий нуль считается концом файла.
Строковые потоки описаны в файле
.
10.5.3 Буферизация
Все операции ввода-вывода были определены без всякой связи с типом файла, но нельзя одинаково
работать со всеми устройствами без учета алгоритма буферизации. Очевидно, что потоку ostream,
привязанному к строке символов, нужен не такой буфер, как ostream, привязанному к файлу. Такие
вопросы решаются созданием во время инициализации разных буферов для потоков разных типов. Но
существует только один набор операций над этими типами буферов, поэтому в ostream нет функций,
код которых учитывает различие буферов. Однако, функции, следящие за переполнением и
обращением к пустому буферу, являются виртуальными. Это хороший пример применения виртуальных
функций для единообразной работы с эквивалентными логически, но различно реализованными
структурами, и они вполне справляются с требуемыми алгоритмами буферизации. Описание буфера
потока в файле может выглядеть следующим образом:
class streambuf {
// управление буфером потока
protected:
char*
base;
//
начало буфера
char*
pptr;
// следующий свободный байт
char*
gptr;
// следующий заполненный байт
char*
eptr;
// один из указателей на конец буфера
char
alloc;
// буфер, размещенный с помощью "new"
//...
// Опустошить буфер:
// Вернуть EOF при ошибке, 0 - удача
virtual int overflow(int c = EOF);
// Заполнить буфер:
// Вернуть EOF в случае ошибки или конца входного потока,
// иначе вернуть очередной символ
virtual
int
underflow();
//...
Бьерн Страуструп.
Язык программирования С++
279
public:
streambuf();
streambuf(char* p, int l);
virtual
~streambuf();
int snextc() // получить очередной символ
{
return (++gptr==pptr) ? underflow() : *gptr&0377;
}
int allocate(); // отвести память под буфер
//...
};
Подробности реализации класса streambuf приведены здесь только для полноты представления. Не
предполагается, что есть общедоступные реализации, использующие именно эти имена. Обратите
внимание на определенные здесь указатели, управляющие буфером; с
их помощью простые
посимвольные операции с потоком можно определить максимально эффективно (и причем однократно)
как функции-подстановки. Только функции overflow() и underflow() требует своей реализации для
каждого алгоритма буферизации, например:
class filebuf : public streambuf {
protected:
int fd; //
дескриптор файла
char opened; // признак открытия файла
public:
filebuf() { opened = 0; }
filebuf(int nfd, char* p, int l)
: streambuf(p,l) { /* ... */ }
~filebuf() { close(); }
int
overflow(int
c=EOF);
int
underflow();
filebuf* open(char *name, ios::open_mode om);
int close() { /* ... */ }
//...
};
int filebuf::underflow() //
заполнить буфер из "fd"
{
if (!opened || allocate()==EOF) return EOF;
int count = read(fd, base, eptr-base);
if (count < 1) return EOF;
gptr = base;
pptr = base + count;
return *gptr & 0377; // &0377 предотвращает размножение знака
}
За дальнейшими подробностями обратитесь к руководству по реализации класса streambuf.
Достарыңызбен бөлісу: