使用xsputn和overflow继承ostream和streambuf问题

Dig*_*ers 6 c++ iostream ostream streambuf

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

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

现在问题就在这里,我需要知道何时将float放入缓冲区.换句话说,我需要知道这是什么时候最后一次溢出将被调用为特定值流入.xsputn对我有用的原因是因为我得到了整个值及其长度.所以我可以将它复制到缓冲区然后调用等待缓冲区已满的函数.

我无可否认地滥用了ostream设计,因为我需要缓存输出然后立即为每个输入值(<<)发送它.

无论如何要清楚我会以另一种方式重申我正在拍摄的内容.我很有可能以错误的方式解决这个问题.

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

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

Jam*_*nze 16

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

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

setbuf:允许客户端代码指定缓冲区.(恕我直言,这通常不值得打扰,但你可能有特殊要求.)

seekoff:支持寻求.我从来没有在我streambuf的任何一个中使用过这个,所以除了你在标准中读到的内容之外,我无法提供任何信息.

sync:调用flush时,应将缓冲区中的任何字符输出到接收器.如果你从不打电话setp(所以没有缓冲区),你总是在同步,这可能是一个无操作. overflow或者uflow可以调用这个,或者两者都可以调用一些单独的函数.(关于sync 和之间的唯一区别uflow是,uflow只有在有缓冲区时才会调用它,如果缓冲区为空,它将永远不会被调用. sync如果客户端代码刷新了流,它将被调用.)

在编写我自己的流时,除非性能另有说明,否则我会保持简单,只能覆盖overflow.如果性能决定了一个缓冲区,我通常会把代码刷新到一个单独的write(address, length) 函数中,overflowsync按照以下方式实现:

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;
}
Run Code Online (Sandbox Code Playgroud)

一般来说,我不会打扰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;
}
Run Code Online (Sandbox Code Playgroud)

  • 代码无法预先知道客户端代码将要执行的操作,或者将要调用多少次.你可以做的是在`ostream`上设置`unitbuf`:这将导致`sync`在每个`operator <<`的末尾被调用(在`sentry`对象的析构函数中).然后在`sync`中对缓冲区执行操作. (2认同)