Шаг 519.
Библиотека STL. Ввод-вывод с использованием потоковых классов. Классы потоковых буферов. Пользовательские буферы вывода (окончание)

    На этом шаге мы закончим изучение пользовательских буферов вывода.

    Чтобы потоковый буфер действительно обеспечивал буферизацию, буфер вывода должен быть инициализирован функцией setp(). В следующем примере показано, как это делается:

#include <cstdio>
#include <streambuf>

extern "C" {
    int write (int fd, const char* buf, int num);
}

class outbuf : public std::streambuf {
  protected:
    static const int bufferSize = 10;   // Размер буфера данных
    char buffer[bufferSize];            // Буфер данных

  public:
    // Конструктор
    // - Инициализация буфера данных
    // - на один символ меньше, чтобы при накоплении bufferSize символов
    //   вызывалась функция overflow()
    outbuf() {
        setp (buffer, buffer+(bufferSize-1));
    }
    // Деструктор
    //  - Очистка буфера данных
    virtual ~outbuf() {
        sync();
    }

  protected:
    // Вывод символов, хранящихся в буфере
    int flushBuffer () {
        int num = pptr()-pbase();
        if (write (1, buffer, num) != num) {
            return EOF;
        }
        pbump (-num);    // Соответствующий перевод указателя вывода
        return num;
    }

    // Буфер полон
    //  - Вывести c и все предшествующие символы
    virtual int_type overflow (int_type c) {
        if (c != EOF) {
            // Вставка символа в буфер
            *pptr() = c;
            pbump(1);
        }
        // Очистка буфера
        if (flushBuffer() == EOF) {
            // ERROR
            return EOF;
        }
        return c;
    }

    // Синхронизация данных с файлом/приемником
    //  - вывод данных из буфера
    virtual int sync () {
        if (flushBuffer() == EOF) {
            // ОШИБКА
            return -1;
        }
        return 0;
    }
};

    Конструктор инициализирует буфер вывода функцией setp():

  setp (buffer, buffer+(bufferSize-1);

    Буфер вывода настроен так, что функция overflow() вызывается, когда еще остается место для одного символа. Если функция overflow() вызывается с аргументом, отличным от EOF, то соответствующий символ может быть помещен в текущую позицию записи, поскольку указатель на нее не выходит за пределы конечного указателя. После того как аргумент overflow() будет помещен в позицию записи, буфер можно очистить.

    Именно эта задача решается функцией flushBuffer(). Функция записывает символы в стандартный канал вывода (дескриптор 1) при помощи функции write(). Функция pbump() потокового буфера возвращает позицию записи к началу буфера.

    Функция overflow() вставляет в буфер символ, ставший причиной вызова overflow(), если он отличен от EOF. Затем функция pbump() смещает текущую позицию записи, чтобы она отражала новый конец блока буферизованных сим-волов. Тем самым позиция записи временно смещается за конечную позицию (epptr()).

    Класс также содержит виртуальную функцию sync(), предназначенную для синхронизации текущего состояния потокового буфера с непосредственным носителем данных. Обычно синхронизация ограничивается простой очисткой буфера. Для небуферизованных версий переопределять эту функцию не обязательно, поскольку нет самого буфера, который можно было бы очистить.

    Виртуальный деструктор обеспечивает вывод данных, остающихся в буфере при его уничтожении.

    Эти функции переопределяются для большинства потоковых буферов. Если внешнее представление имеет особую структуру, возможно, придется переопределить дополнительные функции, например функции seekoff() и seekpos(), для управления позицией записи.

    Со следующего шага мы начнем рассматривать пользовательские буферы ввода.




Предыдущий шаг Содержание Следующий шаг