7

我一直在研究如何创建我自己的 ostream 以及一个 streambuf 来处理我的 ostream 的缓冲区。我实际上大部分都在工作,我可以将 (<<) 插入到我的流中并获取字符串没问题。我通过实现虚函数 xsputn 来做到这一点。但是,如果我在流中输入 (<<) 浮点数或整数,而不是字符串 xsputn 永远不会被调用。

我浏览了代码,我看到流正在调用 do_put,然后是 f_put,它最终尝试一次将 float 1 个字符放入缓冲区。如果我的缓冲区没有空间,我可以让它调用我的虚函数溢出(int c)的实现,从而获得浮点数和整数的数据。

现在问题来了,我需要知道何时将浮点数放入缓冲区。或者换一种说法,我需要知道这是最后一次为流入的特定值调用溢出的时间。xsputn 对我有用的原因是因为我预先获得了整个值及其长度。所以我可以将它复制到缓冲区中,然后调用等待缓冲区已满的函数。

诚然,我滥用了 ostream 设计,因为我需要缓存输出,然后为每个输入值 (<<) 一次性发送所有输出。

无论如何要清楚,我将以另一种方式重申我的目标。我很有可能只是走错路了。

我想使用继承的 ostream 和 streambuf,以便我可以向其中输入值并允许它为我处理我的类型转换,然后我想将该信息传送到另一个对象,我将句柄传递给 streambuf 到(为了?)。该对象具有昂贵的 i/o,因此我不想一次发送 1 个字符的数据。

如果不清楚,请提前抱歉。谢谢你的时间。

4

1 回答 1

17

虽然听起来大致正确,但不太清楚你在做什么。只是为了确定:你ostream所做的只是提供方便的构造函数来创建和安装你的streambuf,一个析构函数,可能还有一个实现rdbuf来处理正确类型的缓冲区。假设这是真的:xsputn在你streambuf的定义纯粹是一种优化。您必须定义的关键功能是overflow. 最简单的实现overflow只需要一个字符,并将其输出到接收器。除此之外的一切都是优化:例如,您可以使用setp;设置缓冲区。如果您这样做,则overflow只会在缓冲区已满或请求刷新时调用。在这种情况下,您还必须输出缓冲区(使用pbasepptr获取地址)。(streambuf基类初始化指针以创建一个长度为 0 的缓冲区,因此overflow将为每个字符调用。)您可能希望在(非常)特定情况下覆盖的其他函数:

imbue:如果您出于某种原因需要语言环境。(请记住,当前字符编码是语言环境的一部分。)

setbuf: 允许客户端代码指定一个缓冲区。(恕我直言,通常不值得费心,但您可能有特殊要求。)

seekoff: 支持求。我从来没有在我的任何一个streambufs中使用过这个,所以我不能提供超出标准中你可以阅读的任何信息。

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;
}
于 2011-04-13T09:24:43.243 回答