虽然听起来大致正确,但不太清楚你在做什么。只是为了确定:你ostream
所做的只是提供方便的构造函数来创建和安装你的streambuf
,一个析构函数,可能还有一个实现rdbuf
来处理正确类型的缓冲区。假设这是真的:xsputn
在你streambuf
的定义纯粹是一种优化。您必须定义的关键功能是overflow
. 最简单的实现overflow
只需要一个字符,并将其输出到接收器。除此之外的一切都是优化:例如,您可以使用setp
;设置缓冲区。如果您这样做,则overflow
只会在缓冲区已满或请求刷新时调用。在这种情况下,您还必须输出缓冲区(使用pbase
和pptr
获取地址)。(streambuf
基类初始化指针以创建一个长度为 0 的缓冲区,因此overflow
将为每个字符调用。)您可能希望在(非常)特定情况下覆盖的其他函数:
imbue
:如果您出于某种原因需要语言环境。(请记住,当前字符编码是语言环境的一部分。)
setbuf
: 允许客户端代码指定一个缓冲区。(恕我直言,通常不值得费心,但您可能有特殊要求。)
seekoff
: 支持求。我从来没有在我的任何一个streambuf
s中使用过这个,所以我不能提供超出标准中你可以阅读的任何信息。
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;
}