Boost logo

Boost :

Subject: [boost] [iostreams] filtering_ostream does not flush std::cout.
From: Duncan Smith (duncanphilipnorman_at_[hidden])
Date: 2010-09-01 10:33:11


I'm using Boost 1.43.0, and I've found that filtering_ostream does not
flush "std::cout".  I found a relevant (and recent) ticket against
Boost 1.44.0, but my issue is slightly different.
 https://svn.boost.org/trac/boost/ticket/4590
I'm using GCC 4.3.4 on Gentoo Linux.

I'm hoping that I'm just doing something wrong, but if you think
there's a bug, I'll add my testcase to the ticket.

The basic recipe:

filtering_ostream out;
out.push(any_filter_at_all());
out.push(std::cout);
out << "Hello World!" << std::flush;
sleep(10); // Observe an empty console.
std::cout << std::flush;
sleep(10); // Observe printed text on console.

This problem is quite bad for me when doing the following on the
command-line (for a more complicated program):
 ./program 2>&1 | tee some-file.log
Because stdout is not getting flushed, the stdout and stderr get
intermingled strangely.

However, disabling buffering on stdout works around the problem:
 stdbuf --output=0 ./program 2>&1 | tee some-file.log

Please tell me if you think there's a bug in my code. If it's a bug
in Boost.Iostreams (or I'm expecting the wrong behaviour), I would
appreciate any ideas for workarounds (I tried cout.setf(unitbuf), and
that doesn't seem to do the trick).

Here's the full text of my code:

------------------
// Test case for flushing a filtering_ostream based on the
// boost_iostreams_filtering_ostream.cpp attached to ticket #4950:
// https://svn.boost.org/trac/boost/ticket/4590
// https://svn.boost.org/trac/boost/attachment/ticket/4590/boost_iostreams_filtering_ostream.cpp
// changed to use "cout" as the sink.
//
// Flushing a filtering_ostream using the flush() global function does not work
// in Boost 1.43. I suspect it also does not work in Boost 1.44.
//
// Using GCC-4.3.4 on Gentoo Linux.
//
#include <cassert>
#include <string>
#include <boost/iostreams/categories.hpp>
#include <boost/iostreams/operations.hpp>
#include <boost/iostreams/filtering_stream.hpp>

#include <iostream>

// Included for "sleep()" call below.
#include <unistd.h>

namespace io = boost::iostreams;

// Simple output filter forwarding just forwarding the put chars to
// the sink.
struct transparent_output_filter {
    typedef char char_type;
    typedef io::output_filter_tag category;

    template <typename Sink>
        bool put(Sink& snk, char c)
        {
            return io::put(snk, c);
        }
};

int main(int argc, char *argv[])
{
    using namespace std;

    io::filtering_stream<io::output> out;

    // Transparent filter just forward the characters to the sink.
    //
    // Note: I observe this behaviour with and without this line.
    out.push(transparent_output_filter());

    // Sink appends characters to "cout".
    out.push(cout);

    // Write test string to filtering_ostream.
    out << "Hello World!";

    // On my system, this will flush the buffer iff I'm on an
    // interactive console. "\n" and endl have the same effect. I believe
    // that my shell sets "stdout" to be line-buffered if it's interactive.
    // out << "\n";

    bool wasFlushed = false;
    // The flush does *not* work in Boost 1.43.
    wasFlushed = io::flush(out);

    // This assertion does not go off, though.
    assert(wasFlushed);

    // This also doesn't work.
    wasFlushed = out.flush();
    assert(wasFlushed);

    // This also doesn't work.
    out << std::flush;

    // Demonstrate that none of the above flush calls had any effect on "cout".
    sleep(10);

    // Now we finally get the characters on the console.
    cout << flush;

    // Demonstrate that the direct flush call works when called directly on
    // "cout".
    sleep(10);

    return 0;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk