Я много раз видел инструкции по созданию пользовательских потоковых буферов: все, что вам нужно сделать, это правильно реализовать overflow
, underflow
и pbackfail
в потомке std::basic_streambuf
, и вы сможете создать поток, который форматирует данные, используя его. Эти три подпрограммы определяют «управляемую последовательность» вашего пользовательского потока.
Но в списке защищенных членов std::basic_streambuf
скрываются и другие монстры, а именно setg
и setp
. Они устанавливают буферные области для ввода и вывода. Публичные члены, которые получают и устанавливают данные, сначала пытаются получить доступ к этим областям, прежде чем перейти к контролируемой последовательности.
Для пары различных пользовательских потоковых буферов могут возникнуть проблемы, если поток устанавливает свои собственные области получения/ввода. Поэтому я хотел бы, чтобы такие потоковые буферы избегали использования областей get/put и всегда использовали overflow
, underflow
и pbackfail
без какой-либо промежуточной буферизации.
Для наивного упрощенного примера, если вы оборачиваете другой streambuf, реализация underflow
может выглядеть так:
template <class C, class TR>
typename TR::int_type wrapping_streambuf<C, TR>::underflow()
{
return m_wrapped_streambuf->sgetc();
}
Пусть обернутый streambuf сделает всю грязную работу. Вот еще один наивный пример подсчета строк:
template <class C, class TR>
typename TR::int_type tracking_streambuf<C, TR>::uflow()
{
auto rv = m_wrapped_streambuf->sbumpc();
if (rv == (TR::int_type)'\n') ++ m_input_line_count;
return rv;
}
Для таких потоков нет полезной реализации setg
, потому что вы не можете получить доступ к внутренней области получения завернутого буфера. Для tracked_streambuf
наложение областей get/put сделало бы невозможным подсчет строк в синхронизации с логической последовательностью потока.
Я думаю, что ответ заключается в том, чтобы никогда не вызывать setg
или setp
в классах-потомках. Фактически, они, вероятно, должны переопределить setg
, setp
, gbump
и pbump
, чтобы генерировать исключения.
Глядя на заголовок <streambuf>
, я вижу, что пользовательский streambuf в реализации моей любимой библиотеки может работать так, как я хочу (есть проверки на null gptr/pptr), если я это сделаю. Но является ли это гарантией?