make the compiler not to automatically flush the b

2019-08-08 02:58发布

Why does the below code not stop the compiler from flushing the buffer automatically?

cout.sync_with_stdio(false);
cin.tie(nullptr);
cout << "hello";
cout << "world";
int a;
cin >> a;

output:

helloworld

I'm using Visual Studio 2012 Ultimate

2条回答
女痞
2楼-- · 2019-08-08 03:09

The standard allows an implementation to flush any time it feels like it, but from a quality of implementation point of view, one really doesn't expect a flush here. You might try adding a setbuf, telling std::cin to use a buffer you specify:

std::cout.rdbuf()->setbuf( buffer, sizeof(buffer) );

Again,the standard doesn't guarantee anything, but if this isn't respected, I'd consider the quality bad enough to warrant a bug report.

Finally, if worse comes to worse, you can always insert a filtering streambuf which does the buffering you want. You shouldn't have to, but it won't be the first time we've had to write extra code to work around a lack of quality in compilers or libraries. If all you're doing is straightforward output (no seeks, or anything, something like the following should do the trick:

class BufferingOutStreambuf : public std::streambuf
{
    std::streambuf* myDest;
    std::ostream* myOwner;
    std::vector<char> myBuffer;

    static size_t const bufferSize = 1000;
protected:
    virtual int underflow( int ch )
    {
        return sync() == -1 
            ? EOF
            : sputc( ch );
    }
    virtual int sync()
    {
        int results = 0;
        if ( pptr() != pbase() ) {
            if ( myDest->sputn( pbase(), pptr() - pbase() )
                    != pptr() - pbase() ) {
                results = -1;
            }
        }
        setp( &myBuffer[0], &myBuffer[0] + myBuffer.size() );
        return results;
    }
public:
    BufferingOutStreambuf( std::streambuf* dest )
        : myDest( dest )
        , myOwner( NULL )
        , myBuffer( bufferSize )
    {
        setp( &myBuffer[0], &myBuffer[0] + myBuffer.size() );
    }

    BufferingOutStreambuf( std::ostream& dest )
        : myDest( dest.rdbuf() )
        , myOwner( &dest )
        , myBuffer( bufferSize )
    {
        setp( &myBuffer[0], &myBuffer[0] + myBuffer.size() );
        myOwner->rdbuf( this );
    }

    ~BufferingOutStreambuf()
    {
        if ( myOwner != NULL ) {
            myOwner->rdbuf( myDest );
        }
    }
};

Then just do:

BufferingOutStreambuf buffer( std::cout );

as the first line in main. (One could argue that iostreams should have been designed to work like this from the start, with filtering streambuf for buffering and code translation. But it wasn't, and this shouldn't be necessary with a decent implementation.)

查看更多
Explosion°爆炸
3楼-- · 2019-08-08 03:17

AFAIK, the stream can be flushed whenever the implementation likes to do so, i.e. there's no guarantee that the stream will be flushed after an insert operation. However, you could use one of these manipulators to ensure your stream gets flushed (these are the only ones I know of so if someone is aware of others, please comment):

  • std::endl - inserts a newline into the stream and flushes it,
  • std::flush - just flushes the stream,
  • std::(no)unitbuf - enables/disables flushing the stream after each insert operation.
查看更多
登录 后发表回答