Не очень понятно, что вы делаете, хотя это звучит примерно правильно.Просто чтобы быть уверенным: все, что делает 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;
}