inheriting ostream and streambuf problem with xsputn and overflow

不想你离开。 提交于 2019-12-04 05:30:13

It's not too clear what you're doing, although it sounds roughly right. Just to be sure: all your ostream does is provide convenience constructors to create and install your streambuf, a destructor, and possibly an implementation of rdbuf to handle buffers of the right type. Supposing that's true: defining xsputn in your streambuf is purely an optimization. The key function you have to define is overflow. The simplest implementation of overflow just takes a single character, and outputs it to the sink. Everything beyond that is optimization: you can, for example, set up a buffer using setp; if you do this, then overflow will only be called when the buffer is full, or a flush was requested. In this case, you'll have to output buffer as well (use pbase and pptr to get the addresses). (The streambuf base class initializes the pointers to create a 0 length buffer, so overflow will be called for every character.) Other functions which you might want to override in (very) specific cases:

imbue: If you need the locale for some reason. (Remember that the current character encoding is part of the locale.)

setbuf: To allow client code to specify a buffer. (IMHO, it's usually not worth the bother, but you may have special requirements.)

seekoff: Support for seeking. I've never used this in any of my streambufs, so I can't give any information beyond what you could read in the standard.

sync: Called on flush, should output any characters in the buffer to the sink. If you never call setp (so there's no buffer), you're always in sync, and this can be a no-op. overflow or uflow can call this one, or both can call some separate function. (About the only difference between sync and uflow is that uflow will only be called if there is a buffer, and it will never be called if the buffer is empty. sync will be called if the client code flushes the stream.)

When writing my own streams, unless performance dictates otherwise, I'll keep it simple, and only override overflow. If performance dictates a buffer, I'll usually put the code to flush the buffer into a separate write(address, length) function, and implement overflow and sync along the lines of:

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;
}

Generally, I'll not bother with xsputn, but if your client code is outputting a lot of long strings, it could be useful. Something like this should do the trick:

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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!