<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2535: Inconsistency between ostream::write and ostream::operator&lt;&lt;</title>
<meta property="og:title" content="Issue 2535: Inconsistency between ostream::write and ostream::operator&lt;&lt;">
<meta property="og:description" content="C++ library issue. Status: NAD">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2535.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#NAD">NAD</a> status.</em></p>
<h3 id="2535"><a href="lwg-closed.html#2535">2535</a>. Inconsistency between <code>ostream::write</code> and <code>ostream::operator&lt;&lt;</code></h3>
<p><b>Section:</b> 27.4.4.4 <a href="https://wg21.link/string.io">[string.io]</a>, 31.7.6.4 <a href="https://wg21.link/ostream.unformatted">[ostream.unformatted]</a> <b>Status:</b> <a href="lwg-active.html#NAD">NAD</a>
 <b>Submitter:</b> Marshall Clow <b>Opened:</b> 2015-09-10 <b>Last modified:</b> 2016-07-13</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#string.io">issues</a> in [string.io].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#NAD">NAD</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Consider the following program:
</p>
<blockquote><pre>
#include &lt;iostream&gt;
#include &lt;ostream&gt;
#include &lt;string&gt;

template &lt;class CharT&gt;
class testbuf : public std::basic_streambuf&lt;CharT&gt; 
{
public:
  testbuf() {}

protected:
  virtual std::streamsize xsputn(const CharT *s, std::streamsize n)
  {
    std::cout &lt;&lt; "xsputn('" &lt;&lt; s &lt;&lt; "', " &lt;&lt; n &lt;&lt; ")\n";
    return n;
  }
};

int main () 
{
  testbuf&lt;char&gt; sb;
  std::ostream os (&amp;sb);
  
  std::string s1{"abc"};
  os.write(s1.data(), s1.size());
  
  os.write(s1.data(), 0);
  
  std::string s2{"def"};
  os &lt;&lt; s2;
  
  std::string s3{""};
  os &lt;&lt; s3;
  
  os &lt;&lt; "";
}
</pre></blockquote>
<p>
What should it print?
<p/>
libc++:
</p>
<blockquote><pre>
xsputn('abc', 3)
xsputn('def', 3)
</pre></blockquote>
<p>
libstdc++:
</p>
<blockquote><pre>
xsputn('abc', 3)
xsputn('abc', 0)
xsputn('def', 3)
xsputn('', 0)
xsputn('', 0)
</pre></blockquote>
<p>
VS:
</p>
<blockquote><pre>
xsputn('abc', 3)
xsputn('def', 3)
xsputn('', 0)
xsputn('', 0)
</pre></blockquote>
<p>
27.4.4.4 <a href="https://wg21.link/string.io">[string.io]</a>/5 seems to say that an implementation is required to call <code>sputn</code> (which calls <code>xsputn</code>) 
even if there's nothing to output (in the case of <code>ostream::operator&lt;&lt;(basic_string)</code>).
<p/>
31.7.6.4 <a href="https://wg21.link/ostream.unformatted">[ostream.unformatted]</a>/5.1 implies that it's OK to not call <code>sputn</code> if there's nothing to output 
(in the case of <code>ostream::write</code>)
<p/>
Backstory: A user has a <code>ostream</code> with a subclass of <code>basic_streambuf</code>. it creates an output file on first write. 
Sometimes, he calls <code>ostream::write(p, 0)</code>, and expects this to create the file. This doesn't work in libc++, and then 
he pointed out the inconsistency between <code>operator&lt;&lt;</code> and <code>write</code>.
<p/>
For reference to a bug report <a href="https://llvm.org/bugs/show_bug.cgi?id=24437">see here</a>.
<p/>
There are two obvious possible resolutions:
</p>
<ol style="list-style-type: none">
<li><p>a) require all output functions to call <code>sputn</code>, even if there are no characters to output. In practice, this 
reduces to "string-like" things which are empty (<code>string</code>, <code>string_view</code>, <code>char*</code>, etc), and 
<code>write(ptr, len)</code>.</p></li>
<li><p>b) remove the requirement that <code>ostream::operator&lt;&lt;</code> call <code>sputn</code> when there are no characters 
to output.</p></li>
</ol>

<p><i>[06-2016 Oulu, Saturday morning]</i></p>

<p>MC: Problem is this program produces different outputs on different platforms. The issue is what happens when you write 0 bytes: do you have to call xsputn? This affects a real customer.</p>
<p>NJ: Why is this a problem? Why not QOI?</p>
<p>DKu: I don’t think it’s a problem.</p>
<p>MC: Making your own streambuf is an explicit customization point.</p>
<p>DKu: But you should expect different numbers of calls.</p>
<p>NJ: They may even split the input, and call xsputn more than once for an input.</p>
<p>MC: Do we actually say that anywhere?</p>
<p>DKu: I think so.</p>
<p>MC: If you can find that, I’d be OK with NAD. The other thing that bothers me is that in one case it says you’re required to call sputn even if there’s no input, but the other wording doesn’t contain that requirement.</p>
<p>DKu: The first wording says “as if by”, which may give wiggle room to not call it.</p>
<p>DKu: In the second wording, sputc will never call sputn; it puts character into buffer, and calls overflow if the buffer is full. sputn is strictly an optimization.</p>
<p>MC: OK, I’m convinced this could be NAD, that the standard simply gives no guarantees about this. Are we OK with this lack of precision and implementation variance, or does the spec need to be more precise?</p>
<p>DKu: If you look at [ostream]/p2, it deliberately doesn’t specify how the functions are called. Even if sputn is called, no guarantee that xsputn is called at all: if there’s space in the buffer, the implementation may just put the characters in the buffer. This flexibility makes user implementations nicer, so I think this is definitely NAD</p>
<p>BD: This stuff is incredibly chewed-over. There used to always be a group working on this stuff; it’s hard to believe there’s anything in here that’s not deliberate, so you can’t change it with this small group; you need to talk to all the implementers.</p>
<p>MC: Any objections to NAD?</p>
<p>no objections.</p>

Closing as NAD.


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





</body>
</html>
