Введение в язык Си++

         

Буферизация


При задании операций ввода/вывода мы никак не касались типов файлов, но ведь не все устройства можно рассматривать одинаково с точки зрения стратегии буферизации. Например, для ostream, подключенного к символьной строке, требуется буферизация другого вида, нежели для ostream, подключенного к файлу. С этими проблемами можно справиться, задавая различные буферные типы для разных потоков в момент инициализации (обратите внимание на три конструктора класса ostream). Есть только один набор операций над этими буферными типами, поэтому в функциях ostream нет кода, их различающего. Однако функции, которые обрабатывают переполнение сверху и снизу, виртуальные. Этого достаточно, чтобы справляться с необходимой в данное время стратегией буферизации. Это также служит хорошим примером применения виртуальных функций для того, чтобы сделать возможной однородную обработку логически эквивалентных средств с различной реализацией. Описание буфера потока в выглядит так:

struct streambuf { // управление буфером потока

char* base; // начало буфера char* pptr; // следующий свободный char char* qptr; // следующий заполненный char char* eptr; // один из концов буфера char alloc; // буфер, выделенный с помощью new

// Опустошает буфер: // Возвращает EOF при ошибке и 0 в случае успеха virtual int overflow(int c =EOF);

// Заполняет буфер // Возвращет EOF при ошибке или конце ввода, // иначе следующий char virtual int underflow();

int snextc() // берет следующий char { return (++qptr==pptr) ? underflow() : *qptr0377 }

// ...

int allocate() // выделяет некоторое пространство буфера

streambuf() { /* ... */} streambuf(char* p, int l) { /* ... */} ~streambuf() { /* ... */} };

Обратите внимание, что здесь определяются указатели, необходимые для работы с буфером, поэтому обычные посимвольные действия можно определить (только один раз) в виде максимально эффективных inline- функций. Для каждой конкретной стратегии буферизации необходимо определять только функции переполнения overflow() и underflow(). Например:

struct filebuf : public streambuf {

int fd; // дескриптор файла char opened; // файл открыт

int overflow(int c =EOF); int underflow();

// ...

// Открывает файл: // если не срабатывает, то возвращает 0, // в случае успеха возвращает "this" filebuf* open(char *name, open_mode om); int close() { /* ... */ }

filebuf() { opened = 0; } filebuf(int nfd) { /* ... */ } filebuf(int nfd, char* p, int l) : (p,l) { /* ... */ } ~filebuf() { close(); } };

int filebuf::underflow() // заполняет буфер из fd { if (!opened allocate()==EOF) return EOF;

int count = read(fd, base, eptr-base); if (count



Содержание раздела