<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 835: Tying two streams together (correction to DR 581)</title>
<meta property="og:title" content="Issue 835: Tying two streams together (correction to DR 581)">
<meta property="og:description" content="C++ library issue. Status: C++11">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue835.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++11">C++11</a> status.</em></p>
<h3 id="835"><a href="lwg-defects.html#835">835</a>. Tying two streams together (correction to DR 581)</h3>
<p><b>Section:</b> 31.5.4.3 <a href="https://wg21.link/basic.ios.members">[basic.ios.members]</a> <b>Status:</b> <a href="lwg-active.html#C++11">C++11</a>
 <b>Submitter:</b> Martin Sebor <b>Opened:</b> 2008-05-17 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#basic.ios.members">issues</a> in [basic.ios.members].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++11">C++11</a> status.</p>
<p><b>Discussion:</b></p>
       <p>

The fix for
issue <a href="lwg-defects.html#581" title="flush() not unformatted function (Status: CD1)">581</a><sup><a href="https://cplusplus.github.io/LWG/issue581" title="Latest snapshot">(i)</a></sup>,
now integrated into the working paper, overlooks a couple of minor
problems.

       </p>
       <p>

First, being an unformatted function once again, <code>flush()</code>
is required to create a sentry object whose constructor must, among
other things, flush the tied stream. When two streams are tied
together, either directly or through another intermediate stream
object, flushing one will also cause a call to <code>flush()</code> on
the other tied stream(s) and vice versa, ad infinitum. The program
below demonstrates the problem.

       </p>
       <p>

Second, as Bo Persson notes in his
comp.lang.c++.moderated <a href="http://groups.google.com/group/comp.lang.c++.moderated/tree/browse_frm/thread/f2187794e9cc036d/305df31dc583054a">post</a>,
for streams with the <code>unitbuf</code> flag set such
as <code>std::stderr</code>, the destructor of the sentry object will
again call <code>flush()</code>. This seems to create an infinite
recursion for <code>std::cerr &lt;&lt; std::flush;</code>

       </p>
       <blockquote>
           <pre>
#include &lt;iostream&gt;

int main ()
{
   std::cout.tie (&amp;std::cerr);
   std::cerr.tie (&amp;std::cout);
   std::cout &lt;&lt; "cout\n";
   std::cerr &lt;&lt; "cerr\n";
} 
</pre>
</blockquote>

<p><i>[
Batavia (2009-05):
]</i></p>

<blockquote><p>
We agree with the proposed resolution.
Move to Review.
</p></blockquote>

<p><i>[
2009-05-26 Daniel adds:
]</i></p>


<blockquote>
<p>
I think that the most recently suggested change in
 [ostream::sentry] need some further word-smithing. As
written, it would make the behavior undefined, if under
conditions when <code>pubsync()</code> should be called, but when
in this scenario <code>os.rdbuf()</code> returns 0.
</p>
<p>
This case is explicitly handled in <code>flush()</code> and needs to be
taken care of. My suggested fix is:
</p>

<blockquote><p>
If <code>((os.flags() &amp; ios_base::unitbuf) &amp;&amp; !uncaught_exception()</code>
<ins><code>&amp;&amp; os.rdbuf() != 0</code></ins>) is true, calls <del><code>os.flush()</code></del>
<ins><code>os.rdbuf()-&gt;pubsync()</code></ins>.
</p></blockquote>

<p>
Two secondary questions are:
</p>

<ol>
<li>
Should <code>pubsync()</code> be invoked in any case or shouldn't a
base requirement for this trial be that <code>os.good() == true</code>
as required in the original <code>flush()</code> case?
</li>
<li>
Since <code>uncaught_exception()</code> is explicitly tested, shouldn't
a return value of -1 of <code>pubsync()</code> produce <code>setstate(badbit)</code>
(which may throw <code>ios_base::failure</code>)?
</li>
</ol>
</blockquote>

<p><i>[
2009-07 Frankfurt:
]</i></p>


<blockquote>
<p>
Daniel volunteered to modify the proposed resolution to address his two questions.
</p>
<p>
Move back to Open.
</p>
</blockquote>

<p><i>[
2009-07-26 Daniel provided wording.  Moved to Review.
]</i></p>


<p><i>[
2009-10-13 Daniel adds:
]</i></p>


<blockquote><p>
This proposed wording is written to match the outcome
of <a href="lwg-closed.html#397" title="ostream::sentry dtor throws exceptions (Status: NAD Editorial)">397</a><sup><a href="https://cplusplus.github.io/LWG/issue397" title="Latest snapshot">(i)</a></sup>.
</p></blockquote>

<p><i>[
2009 Santa Cruz:
]</i></p>


<blockquote><p>
Move to Open. Martin to propose updated wording that will also resolve
issue <a href="lwg-closed.html#397" title="ostream::sentry dtor throws exceptions (Status: NAD Editorial)">397</a><sup><a href="https://cplusplus.github.io/LWG/issue397" title="Latest snapshot">(i)</a></sup> consistently.
</p></blockquote>

<p><i>[
2010-02-15 Martin provided wording.
]</i></p>


<p><i>[
2010 Pittsburgh:
]</i></p>


<blockquote><p>
Moved to Ready for Pittsburgh.
</p></blockquote>



<p id="res-835"><b>Proposed resolution:</b></p>

<ol>
<li>
<p>
Just before 31.5.4.3 <a href="https://wg21.link/basic.ios.members">[basic.ios.members]</a> p. 2 insert a new paragraph:
</p>

<blockquote><p>
<ins><i>Requires:</i> If <code>(tiestr != 0)</code> is <code>true</code>,
<code>tiestr</code> must not be reachable by traversing the linked list of tied
stream objects starting from <code>tiestr-&gt;tie()</code>.</ins>
</p></blockquote>
</li>

<li>
<p>
Change  [ostream::sentry] p. 4 as indicated:
</p>

<blockquote><p>
If <code>((os.flags() &amp; ios_base::unitbuf) &amp;&amp; !uncaught_exception()
<ins>&amp;&amp; os.good()</ins>)</code> is <code>true</code>, calls
<del><code>os.flush()</code></del> <ins><code>os.rdbuf()-&gt;pubsync()</code>. If that
function returns -1 sets <code>badbit</code> in <code>os.rdstate()</code> without
propagating an exception</ins>.
</p></blockquote>
</li>

<li>
<p>
Add after  [ostream::sentry] p17, the following paragraph:
</p>

<blockquote><p>
<ins><i>Throws:</i> Nothing.</ins>
</p></blockquote>

</li>

</ol>


   



</body>
</html>
