Boost C++ Libraries: Ticket #4728: "iostreams::detail::mode_adapter<>" is never "flushable": flushing a filtering_ostream will not flush the "std::ostream" target --- patch included. https://svn.boost.org/trac10/ticket/4728 <p> I have found a problem with Boost.Iostreams. </p> <ul><li>I'm using Boost v1.43.0 on Gentoo Linux with <code>gcc-4.3.4</code>. <ul><li>I've reproduced it with <code>gcc-4.4.3</code>. </li><li>I've reproduced it with Boost v1.44.0 (from the website tarball). </li><li>Let me know if you need to know anything else about my environment. </li></ul></li><li>A simple testcases attached at <a class="attachment" href="https://svn.boost.org/trac10/attachment/ticket/4728/boost_iostreams_filtering_std_ostream.cpp" title="Attachment 'boost_iostreams_filtering_std_ostream.cpp' in Ticket #4728">boost_iostreams_filtering_std_ostream.cpp</a><a class="trac-rawlink" href="https://svn.boost.org/trac10/raw-attachment/ticket/4728/boost_iostreams_filtering_std_ostream.cpp" title="Download">​</a>. </li><li>A patch to fix the problem is attached at <a class="attachment" href="https://svn.boost.org/trac10/attachment/ticket/4728/boost_iostreams-mode_adaptor-flushable.patch" title="Attachment 'boost_iostreams-mode_adaptor-flushable.patch' in Ticket #4728">boost_iostreams-mode_adaptor-flushable.patch</a><a class="trac-rawlink" href="https://svn.boost.org/trac10/raw-attachment/ticket/4728/boost_iostreams-mode_adaptor-flushable.patch" title="Download">​</a>. </li><li>This is a different problem from <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/4590" title="#4590: Bugs: Flushing a filtering_ostream stopped working in Boost 1.44 (closed: fixed)">#4590</a>. </li></ul><h3 class="section" id="Details">Details</h3> <p> I'm going to use <code>io</code> as a synonym for the <code>boost::iostreams</code> namespace. </p> <p> I have come across a problem with <code>io::detail::mode_adapter&lt;Mode, T&gt;</code>, where <code>T</code> is a <code>std::ostream</code> or a <code>std::streambuf</code>. I came across the problem in <code>io::filtering_ostream</code>, but perhaps this class is used elsewhere also. </p> <ul><li><code>io::detail::mode_adapter&lt;&gt;::category</code> is not convertible to any of <code>io::flushable_tag</code>, <code>io::ostream_tag</code>, or <code>io::streambuf_tag</code>. </li><li><code>io::flush()</code> will use <code>io::detail::flush_device_impl&lt;io::any_tag&gt;::flush()</code> for <code>mode_adapter&lt;, T&gt;</code> even when <code>T::catagory</code> is convertible <code>flushable_tag</code>, <code>ostream_tag</code> or <code>streambuf_tag</code>. </li><li>As a result, <code>io::filtering_ostream</code> will not flush correctly when the device at the end of the chain is a non-boost <code>std::ostream</code> or a <code>std::streambuf</code>. <ul><li>I expect, also, that any filters in the chain that inherit from <code>flushable_tag</code> also do not get flushed correctly. </li></ul></li><li>In particular the following methods from the STL <code>std::ostream</code> interface will <em>not</em> flush the stream to the device: <div class="wiki-code"><div class="code"><pre><span class="n">std</span><span class="o">::</span><span class="n">ostream</span> <span class="n">stream</span><span class="p">(</span><span class="o">&amp;</span><span class="n">someBuffer</span><span class="p">);</span> <span class="n">io</span><span class="o">::</span><span class="n">filtering_ostream</span> <span class="n">out</span><span class="p">;</span> <span class="n">out</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">stream</span><span class="p">);</span> <span class="c1">// These STL methods of flushing a stream will NOT flush &quot;stream&quot;.</span> <span class="n">out</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="n">out</span><span class="p">.</span><span class="n">flush</span><span class="p">();</span> </pre></div></div></li><li>My solution is to have <code>mode_adapter&lt;&gt;::category</code> inherit from <code>flushable_tag</code> when appropriate, and to implement <code>::flush()</code> methods: <div class="wiki-code"></div></li></ul> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/4728 Trac 1.4.3 Duncan Exon Smith <duncanphilipnorman@…> Tue, 12 Oct 2010 21:52:59 GMT attachment set https://svn.boost.org/trac10/ticket/4728 https://svn.boost.org/trac10/ticket/4728 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">boost_iostreams-mode_adaptor-flushable.patch</span> </li> </ul> <p> Patch to fix <code>boost::iostreams::detail::mode_adapter&lt;&gt;</code> to be <code>flushable</code> when appropriate. </p> Ticket Duncan Exon Smith <duncanphilipnorman@…> Tue, 12 Oct 2010 21:53:46 GMT attachment set https://svn.boost.org/trac10/ticket/4728 https://svn.boost.org/trac10/ticket/4728 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">boost_iostreams_filtering_std_ostream.cpp</span> </li> </ul> <p> Testcase to show that a <code>filtering_ostream</code> with a non-boost <code>std::ostream</code> device will not flush. </p> Ticket Steven Watanabe Fri, 11 Feb 2011 15:31:09 GMT <link>https://svn.boost.org/trac10/ticket/4728#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4728#comment:1</guid> <description> <p> I'm not convinced that stream <em>should</em> be flushed in this case. </p> </description> <category>Ticket</category> </item> <item> <author>Duncan Exon Smith <duncanphilipnorman@…></author> <pubDate>Fri, 11 Feb 2011 16:40:51 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4728#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4728#comment:2</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/4728#comment:1" title="Comment 1">steven_watanabe</a>: </p> <blockquote class="citation"> <p> I'm not convinced that stream <em>should</em> be flushed in this case. </p> </blockquote> <p> For clarity, do you mean that you're not convinced the stream should be flushed in the following case? </p> <div class="wiki-code"><div class="code"><pre><span class="n">io</span><span class="o">::</span><span class="n">filtering_ostream</span> <span class="n">out</span><span class="p">;</span> <span class="c1">// Insert 0 or more calls to &quot;out.push(SomeFlushableFilter())&quot; here.</span> <span class="n">out</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="p">);</span> <span class="n">out</span> <span class="o">&lt;&lt;</span> <span class="s">&quot;a b c&quot;</span><span class="p">;</span> <span class="n">out</span><span class="p">.</span><span class="n">flush</span><span class="p">();</span> </pre></div></div><p> If so, can you give the reasons why not to flush? If not, then can you expand on which case you were talking about? </p> <p> Here is why I think it <em>should</em> be flushed in the above case: </p> <ol><li>The programmer has asked for the stream to be flushed. <ul><li>Furthermore, <code>std::ostream</code> (thus, <code>std::cout</code>) has the capability of being flushed (it's "flushable"). That it doesn't explicitly have the <code>flushable_tag</code> is simply consequence of it being part of the STL. <ul><li>See <code>boost/iostreams/flush.hpp</code>: <code>boost::flush()</code> will correctly flush <code>std::ostream</code>. </li></ul></li><li>In my opinion, the simplest interpretation of the API is that <code>std::cout</code> would be flushed in this case. <ul><li>Why would the library flush <code>std::ostream</code>, but not a wrapper of <code>std::ostream</code> that is an implementation detail? (I previously assumed that this was an overlooked corner case, not an intentional behaviour. Was I wrong? What's the upside?) </li><li>Is there some other wrapper that the programmer could request use of? I'm thinking something like the following, that perhaps I missed in the documentation: <div class="wiki-code"><div class="code"><pre><span class="n">out</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">noignoreflush</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="p">));</span> </pre></div></div>I maintain that it would be simpler if flushable objects were flushed by default. Something like the following could be used in the rare case that flushing requests should be ignored: <div class="wiki-code"><div class="code"><pre><span class="n">out</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">noflush</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="p">));</span> </pre></div></div></li></ul></li></ul></li><li>There isn't a technical challenge (unless my patch missed a corner case; I am not an expert). </li><li>When a stream is used as a communication channel with another process and timing matters (for example, if there is a handshake, deadlock is bad), not flushing in this case precludes the use of <code>filtering_stream&lt;&gt;</code> with a <code>std::ostream</code> sink. <ul><li>In my opinion, this is an unnecessary restriction on the use of <code>filtering_stream&lt;&gt;</code>. </li><li>Another example: with the current behaviour, it is dangerous to use <code>filtering_stream&lt;&gt;</code> to add timestamps at the beginning of every line of program output. Even if the programmer reliably flushes the stream, the output cannot be viewed in real time. </li></ul></li></ol> </description> <category>Ticket</category> </item> <item> <author>boost@…</author> <pubDate>Fri, 21 Oct 2011 18:17:02 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4728#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4728#comment:3</guid> <description> <p> If this patch is not accepted, what is the canonical way of attaching cerr to a filtered stream so that it will flush properly. Is there a work around? </p> </description> <category>Ticket</category> </item> <item> <author>Duncan Exon Smith <duncanphilipnorman@…></author> <pubDate>Fri, 21 Oct 2011 19:04:06 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4728#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4728#comment:4</guid> <description> <p> I couldn't find a workaround that did not use a patched header. </p> <p> For my projects, I include a patched copy of <code>mode_adaptor.hpp</code> in an overlay (i.e., <code>$MY_PROJECT/boost/iostreams/detail/adapter/mode_adapter.hpp</code>). Since headers in <code>$MY_PROJECT</code> get precedence over system headers (i.e., I pass <code>-I.</code> to GCC), the patched version gets used automatically. </p> <p> The bad news is that you need to maintain the patched version of <code>mode_adaptor.hpp</code> yourself when you upgrade Boost. </p> </description> <category>Ticket</category> </item> <item> <author>Ignacy Gawędzki <boost-bugs@…></author> <pubDate>Wed, 09 May 2012 20:47:16 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4728#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4728#comment:5</guid> <description> <p> I happen to have exactly this problem. I applied the patch and it works for me. Could someone review it and reply, please? </p> <p> Thanks. </p> </description> <category>Ticket</category> </item> <item> <author>Ignacy Gawędzki <boost-bugs@…></author> <pubDate>Wed, 09 May 2012 20:47:59 GMT</pubDate> <title>cc set https://svn.boost.org/trac10/ticket/4728#comment:6 https://svn.boost.org/trac10/ticket/4728#comment:6 <ul> <li><strong>cc</strong> <span class="trac-author">boost-bugs@…</span> added </li> </ul> Ticket Ignacy Gawędzki <boost-bugs@…> Wed, 09 May 2012 20:48:53 GMT version changed https://svn.boost.org/trac10/ticket/4728#comment:7 https://svn.boost.org/trac10/ticket/4728#comment:7 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.44.0</span> → <span class="trac-field-new">Boost Development Trunk</span> </li> </ul> Ticket