наследование проблемы ostream и streambuf с xsputn и переполнением - PullRequest
6 голосов
/ 13 апреля 2011

Я проводил исследования по созданию своего собственного ostream и наряду с этим потокового буфера для обработки буфера для моего ostream.У меня на самом деле большая часть работает, я могу вставить (<<) в свой поток и получить строки без проблем.Я делаю это, реализуя виртуальную функцию xsputn.Однако, если я введу (<<) значение float или int в поток вместо строки, xsputn никогда не будет вызван.</p>

Я прошелся по коду и вижу, что поток вызывает do_put, а затем f_put, который в конечном итоге пытается поместить по одному символу с плавающей точкой в ​​буфер за раз.Я могу заставить его вызывать мою реализацию переполнения виртуальной функции (int c), если я оставляю свой буфер без пробелов и тем самым получаю данные для float и int.

Теперь вот проблема, янужно знать, когда поплавок готов, будучи помещенным в буфер.Или, другими словами, мне нужно знать, когда это будет последний раз, когда будет вызвано переполнение для конкретного потока, передаваемого в поток. Причина, по которой xsputn работает для меня, заключается в том, что я заранее получаю все значение и его длину.Поэтому я могу скопировать его в буфер и вызвать функцию, ожидающую заполнения буфера.

Я по общему признанию злоупотребляю дизайном ostream тем, что мне нужно кэшировать вывод, а затем отправлять все сразу для каждого введенного значения (<<).</p>

В любом случае, чтобы быть ясным, я переформулирую то, для чего стреляю по-другому.Есть очень хороший шанс, что я просто ошибаюсь.

Я хочу использовать унаследованный ostream и streambuf, чтобы я мог вводить значения в него и позволять ему обрабатывать преобразование типов для меня, а затемЯ хочу передать эту информацию другому объекту, которому я передаю дескриптор потоковому буферу (для?).Этот объект имеет дорогой ввод / вывод, поэтому я не хочу отправлять данные по 1 символу за раз.

Заранее извините, если это неясно.И спасибо за ваше время.

1 Ответ

16 голосов
/ 13 апреля 2011

Не очень понятно, что вы делаете, хотя это звучит примерно правильно.Просто чтобы быть уверенным: все, что делает ostream, - это предоставляет удобные конструкторы для создания и установки вашего streambuf, деструктора и, возможно, реализации rdbuf для обработки буферов нужного типа.Предположим, что это правда: определение xsputn в вашем streambuf - это просто оптимизация.Ключевая функция, которую вы должны определить: overflow.Самая простая реализация overflow просто берет один символ и выводит его в приемник.Все, кроме этого, является оптимизацией: вы можете, например, установить буфер, используя setp;если вы сделаете это, то overflow будет вызываться только тогда, когда буфер заполнен или была запрошена очистка.В этом случае вам также потребуется вывести буфер (используйте pbase и pptr для получения адресов).(Базовый класс streambuf инициализирует указатели для создания буфера длиной 0, поэтому overflow будет вызываться для каждого символа.) Другие функции, которые вы можете переопределить в (очень) определенных случаях:

imbue: Если вам по какой-либо причине вам нужен язык.(Помните, что текущая кодировка символов является частью локали.)

setbuf: чтобы разрешить клиентскому коду указывать буфер.(ИМХО, как правило, это не стоит беспокоиться, но у вас могут быть особые требования.)

seekoff: поддержка поиска.Я никогда не использовал это ни в одном из моих streambuf с, поэтому я не могу дать никакой информации, кроме той, которую вы могли бы прочитать в стандарте.

sync: вызывается при сбросе, должны выводить любые символыв буфере к раковине.Если вы никогда не звоните setp (так что нет буфера), вы всегда синхронизированы, и это может быть неоперацией.overflow или uflow могут вызывать эту функцию, либо обе могут вызывать отдельные функции.(Единственное отличие между sync и uflow состоит в том, что uflow будет вызываться только при наличии буфера, и никогда не будет вызываться, если буфер пуст. sync будет вызываться, если код клиентаочищает поток.) ​​

Когда пишу свои собственные потоки, если производительность не требует иного, я оставлю это простым и переопределю только overflow.Если производительность определяет буфер, я обычно помещаю код для сброса буфера в отдельную функцию write(address, length) и реализую overflow и sync в соответствии с:

int MyStreambuf::overflow( int ch )
{
    if ( pbase() == NULL ) {
        // save one char for next overflow:
        setp( buffer, buffer + bufferSize - 1 );
        if ( ch != EOF ) {
            ch = sputc( ch );
        } else {
            ch = 0;
        }
    } else {
        char* end = pptr();
        if ( ch != EOF ) {
            *end ++ = ch;
        }
        if ( write( pbase(), end - pbase() ) == failed ) {
            ch = EOF;
        } else if ( ch == EOF ) {
            ch = 0;
        }
        setp( buffer, buffer + bufferSize - 1 );
    }
    return ch;
}

int sync()
{
    return (pptr() == pbase()
            || write( pbase(), pptr() - pbase() ) != failed)
        ? 0
        : -1;
}

Обычно,Я не буду беспокоиться о xsputn, но если ваш клиентский код выводит много длинных строк, это может быть полезно.Нечто подобное должно сработать:

streamsize xsputn(char const* p, streamsize n)
{
    streamsize results = 0;
    if ( pptr() == pbase()
            || write( pbase(), pptr() - pbase() ) != failed ) {
        if ( write(p, n) != failed ) {
            results = n;
        }
    }
    setp( buffer, buffer + bufferSize - 1 );
    return results;
}
...