<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 432: stringbuf::overflow() makes only one write position available</title>
<meta property="og:title" content="Issue 432: stringbuf::overflow() makes only one write position available">
<meta property="og:description" content="C++ library issue. Status: CD1">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue432.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#CD1">CD1</a> status.</em></p>
<h3 id="432"><a href="lwg-defects.html#432">432</a>. stringbuf::overflow() makes only one write position available</h3>
<p><b>Section:</b> 31.8.2.5 <a href="https://wg21.link/stringbuf.virtuals">[stringbuf.virtuals]</a> <b>Status:</b> <a href="lwg-active.html#CD1">CD1</a>
 <b>Submitter:</b> Christian W Brock <b>Opened:</b> 2003-09-24 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View other</b> <a href="lwg-index-open.html#stringbuf.virtuals">active issues</a> in [stringbuf.virtuals].</p>
<p><b>View all other</b> <a href="lwg-index.html#stringbuf.virtuals">issues</a> in [stringbuf.virtuals].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#CD1">CD1</a> status.</p>
<p><b>Discussion:</b></p>
<p>27.7.1.3 par 8 says:</p>
<blockquote><p>
Notes: The function can make a write position available only if
    ( mode &amp; ios_base::out) != 0. To make a write position
    available, the function reallocates (or initially allocates) an
    array object with a sufficient number of elements to hold the
    current array object (if any), plus one additional write position.
    If ( mode &amp; ios_base::in) != 0, the function alters the read end
    pointer egptr() to point just past the new write position (as
    does the write end pointer epptr()).
</p></blockquote>

<p>
The sentences "plus one additional write position." and especially
    "(as does the write end pointer epptr())" COULD by interpreted
    (and is interpreted by at least my library vendor) as:
</p>

<blockquote><p>
    post-condition: epptr() == pptr()+1
</p></blockquote>

<p>
This WOULD force sputc() to call the virtual overflow() each time.
</p>

<p>The proposed change also affects Defect Report 169.</p>



<p id="res-432"><b>Proposed resolution:</b></p>
<p>27.7.1.1/2 Change:</p>

<blockquote><p>
2- Notes: The function allocates no array object.
</p></blockquote>

<p>
to:
</p>

<blockquote><p>
2- Postcondition: str() == "".
</p></blockquote>

<p>
27.7.1.1/3 Change:
</p>

<blockquote>
<p>
-3- Effects: Constructs an object of class basic_stringbuf,
initializing the base class with basic_streambuf()
(lib.streambuf.cons), and initializing mode with which . Then copies
the content of str into the basic_stringbuf underlying character
sequence and initializes the input and output sequences according to
which. If which &amp; ios_base::out is true, initializes the output
sequence with the underlying sequence. If which &amp; ios_base::in is
true, initializes the input sequence with the underlying sequence.
</p>
</blockquote>

<p>to:</p>

<blockquote>
<p>
-3- Effects: Constructs an object of class basic_stringbuf,
initializing the base class with basic_streambuf()
(lib.streambuf.cons), and initializing mode with which. Then copies
the content of str into the basic_stringbuf underlying character
sequence. If which &amp; ios_base::out is true, initializes the output
sequence such that pbase() points to the first underlying character,
epptr() points one past the last underlying character, and if (which &amp;
ios_base::ate) is true, pptr() is set equal to
epptr() else pptr() is set equal to pbase(). If which &amp; ios_base::in
is true, initializes the input sequence such that eback() and gptr()
point to the first underlying character and egptr() points one past
the last underlying character.
</p>
</blockquote>

<p>27.7.1.2/1 Change:</p>

<blockquote>
<p>
-1- Returns: A basic_string object whose content is equal to the
basic_stringbuf underlying character sequence. If the buffer is only
created in input mode, the underlying character sequence is equal to
the input sequence; otherwise, it is equal to the output sequence. In
case of an empty underlying character sequence, the function returns
basic_string&lt;charT,traits,Allocator>().
</p>
</blockquote>

<p>to:</p>

<blockquote>
<p>
-1- Returns: A basic_string object whose content is equal to the
basic_stringbuf underlying character sequence. If the basic_stringbuf
was created only in input mode, the resultant basic_string contains
the character sequence in the range [eback(), egptr()).  If the
basic_stringbuf was created with (which &amp; ios_base::out) being true
then the resultant basic_string contains the character sequence in the
range [pbase(), high_mark) where high_mark represents the position one
past the highest initialized character in the buffer.  Characters can
be initialized either through writing to the stream, or by
constructing the basic_stringbuf with a basic_string, or by calling
the str(basic_string) member function.  In the case of calling the
str(basic_string) member function, all characters initialized prior to
the call are now considered uninitialized (except for those
characters re-initialized by the new basic_string).  Otherwise the
basic_stringbuf has been created in neither input nor output mode and
a zero length basic_string is returned.
</p>
</blockquote>

<p>
27.7.1.2/2 Change:
</p>

<blockquote>
<p>
-2- Effects: If the basic_stringbuf's underlying character sequence is
not empty, deallocates it. Then copies the content of s into the
basic_stringbuf underlying character sequence and initializes the
input and output sequences according to the mode stored when creating
the basic_stringbuf object. If (mode&amp;ios_base::out) is true, then
initializes the output sequence with the underlying sequence. If
(mode&amp;ios_base::in) is true, then initializes the input sequence with
the underlying sequence.
</p>
</blockquote>

<p>to:</p>

<blockquote>
<p>
-2- Effects: Copies the content of s into the basic_stringbuf
underlying character sequence. If mode &amp; ios_base::out is true,
initializes the output sequence such that pbase() points to the first
underlying character, epptr() points one past the last underlying
character, and if (mode &amp; ios_base::ate) is true,
pptr() is set equal to epptr() else pptr() is set equal to pbase(). If
mode &amp; ios_base::in is true, initializes the input sequence such that
eback() and gptr() point to the first underlying character and egptr()
points one past the last underlying character.
</p>
</blockquote>

<p>Remove 27.2.1.2/3.  (Same rationale as issue 238: incorrect and unnecessary.)</p>

<p>27.7.1.3/1 Change:</p>

<blockquote>
<p>
1- Returns: If the input sequence has a read position available,
returns traits::to_int_type(*gptr()).  Otherwise, returns
traits::eof().
</p>
</blockquote>

<p>to:</p>

<blockquote>
<p>
1- Returns: If the input sequence has a read position available,
returns traits::to_int_type(*gptr()).  Otherwise, returns
traits::eof().  Any character in the underlying buffer which has been
initialized is considered to be part of the input sequence.
</p>
</blockquote>

<p>27.7.1.3/9 Change:</p>

<blockquote>
<p>
-9- Notes: The function can make a write position available only if (
mode &amp; ios_base::out) != 0. To make a write position available, the
function reallocates (or initially allocates) an array object with a
sufficient number of elements to hold the current array object (if
any), plus one additional write position. If ( mode &amp; ios_base::in) !=
0, the function alters the read end pointer egptr() to point just past
the new write position (as does the write end pointer epptr()).
</p>
</blockquote>

<p>to:</p>

<blockquote>
<p>
-9- The function can make a write position available only if ( mode &amp;
ios_base::out) != 0. To make a write position available, the function
reallocates (or initially allocates) an array object with a sufficient
number of elements to hold the current array object (if any), plus one
additional write position. If ( mode &amp; ios_base::in) != 0, the
function alters the read end pointer egptr() to point just past the
new write position.
</p>
</blockquote>

<p>27.7.1.3/12 Change:</p>

<blockquote>
<p>
-12- _ If (newoff + off) &lt; 0, or (xend - xbeg) &lt; (newoff + off), the
positioning operation fails. Otherwise, the function assigns xbeg +
newoff + off to the next pointer xnext .
</p>
</blockquote>

<p>to:</p>

<blockquote>
<p>
-12- _ If (newoff + off) &lt; 0, or if (newoff + off) refers to an
uninitialized character (as defined in 31.8.2.4 <a href="https://wg21.link/stringbuf.members">[stringbuf.members]</a>
paragraph 1), the positioning operation fails. Otherwise, the function
assigns xbeg + newoff + off to the next pointer xnext .
</p>
</blockquote>

<p><i>[post-Kona: Howard provided wording.  At Kona the LWG agreed that
  something along these lines was a good idea, but the original
  proposed resolution didn't say enough about the effect of various
  member functions on the underlying character sequences.]</i></p>




<p><b>Rationale:</b></p>
<p>The current basic_stringbuf description is over-constrained in such
a way as to prohibit vendors from making this the high-performance
in-memory stream it was meant to be.  The fundamental problem is that
the pointers: eback(), gptr(), egptr(), pbase(), pptr(), epptr() are
observable from a derived client, and the current description
restricts the range [pbase(), epptr()) from being grown geometrically.
This change allows, but does not require, geometric growth of this
range.</p>

<p>Backwards compatibility issues: These changes will break code that
derives from basic_stringbuf, observes epptr(), and depends upon
[pbase(), epptr()) growing by one character on each call to overflow()
(i.e. test suites).  Otherwise there are no backwards compatibility
issues.</p>

<p>27.7.1.1/2: The non-normative note is non-binding, and if it were
binding, would be over specification.  The recommended change focuses
on the important observable fact.</p>

<p>27.7.1.1/3: This change does two things: 1.  It describes exactly
what must happen in terms of the sequences.  The terms "input
sequence" and "output sequence" are not well defined.  2.  It
introduces a common extension: open with app or ate mode.  I concur
with issue 238 that paragraph 4 is both wrong and unnecessary.</p>

<p>27.7.1.2/1: This change is the crux of the efficiency issue.  The
resultant basic_string is not dependent upon epptr(), and thus
implementors are free to grow the underlying buffer geometrically
during overflow() *and* place epptr() at the end of that buffer.</p>

<p>27.7.1.2/2:  Made consistent with the proposed 27.7.1.1/3.</p>

<p>27.7.1.3/1: Clarifies that characters written to the stream beyond
the initially specified string are available for reading in an i/o
basic_streambuf.</p>

<p>27.7.1.3/9: Made normative by removing "Notes:", and removed the
trailing parenthetical comment concerning epptr().</p>

<p>27.7.1.3/12: Restricting the positioning to [xbeg, xend) is no
longer allowable since [pbase(), epptr()) may now contain
uninitialized characters.  Positioning is only allowable over the
initialized range.</p>





</body>
</html>
