10.5.3 Буферизация.

   


Назад  |  Вперёд

Все операции ввода-вывода были определены без всякой связи с типом файла, но нельзя одинаково работать со всеми устройствами без учета алгоритма буферизации. Очевидно, что потоку ostream, привязанному к строке символов, нужен не такой буфер, как ostream, привязанному к файлу. Такие вопросы решаются созданием во время инициализации разных буферов для потоков разных типов. Но существует только один набор операций над этими типами буферов, поэтому в ostream нет функций, код которых учитывает различие буферов. Однако, функции, следящие за переполнением и обращением к пустому буферу, являются виртуальными. Это хороший пример применения виртуальных функций для единообразной работы с эквивалентными логически, но различно реализованными структурами, и они вполне справляются с требуемыми алгоритмами буферизации. Описание буфера потока в файле <iostream.h> может выглядеть следующим образом:

           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();
            //...
            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.


Назад  |  Вперёд


OtDiatlovaOU
К началу книги

Оформление и дизайн книги OtDiatlovaOU.
Вся книга, архив.