This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++11 status.

### 1448. Concerns about `basic_stringbuf::str(basic_string)` postconditions

Section: 31.8.2.4 [stringbuf.members] Status: C++11 Submitter: BSI Opened: 2010-08-25 Last modified: 2016-01-28

Priority: Not Prioritized

View all issues with C++11 status.

Discussion:

Addresses GB-124

N3092 31.8.2.4 [stringbuf.members] contains this text specifying the postconditions of `basic_stringbuf::str(basic_string)`:

> Postconditions: If `mode & ios_base::out` is `true`, `pbase()` points to the first underlying character and `epptr() >= pbase() + s.size()` holds; in addition, if `mode & ios_base::in` is `true`, `pptr() == pbase() + s.data()` holds, otherwise `pptr() == pbase()` is `true`. [...]

Firstly, there's a simple mistake: It should be `pbase() + s.length()`, not `pbase() + s.data()`.

Secondly, it doesn't match existing implementations. As far as I can tell, GCC 4.5 does not test for `mode & ios_base::in` in the second part of that sentence, but for `mode & (ios_base::app | ios_base_ate)`, and Visual C++ 9 for `mode & ios_base::app`. Besides, the wording of the C++0x draft doesn't make any sense to me. I suggest changing the second part of the sentence to one of the following:

Replace `ios_base::in` with `(ios_base::ate | ios_base::app)`, but this would require Visual C++ to change (replacing only with `ios_base::ate` would require GCC to change, and would make `ios_base::app` completely useless with `stringstreams`):

in addition, if `mode & (ios_base::ate | ios_base::app)` is `true`, `pptr() == pbase() + s.length()` holds, otherwise `pptr() == pbase()` is `true`.

Leave `pptr()` unspecified if `mode & ios_base::app`, but not `mode & ios_base::ate` (implementations already differ in this case, and it is always possible to use `ios_base::ate` to get the effect of appending, so it is not necessary to require any implementation to change):

in addition, if `mode & ios_base::ate` is `true`, `pptr() == pbase() + s.length()` holds, if neither `mode & ios_base::ate` nor `mode & ios_base::app` is `true`, `pptr() == pbase()` holds, otherwise `pptr() >= pbase() && pptr() <= pbase() + s.length()` (which of the values in this range is unspecified).

Slightly stricter:

in addition, if `mode & ios_base::ate` is `true`, `pptr() == pbase() + s.length()` holds, if neither `mode & ios_base::ate` nor `mode & ios_base::app` is `true`, `pptr() == pbase()` holds, otherwise `pptr() == pbase() || pptr() == pbase() + s.length()` (which of these two values is unspecified). A small table might help to better explain the three cases. BTW, at the end of the postconditions is this text: "`egptr() == eback() + s.size()` hold". Is there a perference for `basic_string::length` or `basic_string::size`? It doesn't really matter, but it looks a bit inconsistent.

[2011-03-09: Nicolai Josuttis comments and drafts wording]

First, it seems the current wording is just an editorial mistake. When we added issue 432 to the draft standard (in n1733), the wording in the issue:

> If `mode & 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 & ios_base::ate)` is true, `pptr()` is set equal to `epptr()` else `pptr()` is set equal to `pbase()`.

became:

> If `mode & 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 `pptr()` is equal to `epptr()` if `mode & ios_base::in` is true, otherwise `pptr()` is equal to `pbase()`.

which beside some changes of the order of words changed

>     ios_base::ate

into

>     ios_base::in

So, from this point of view, clearly `mode & ios_base::ate` was meant.

Nevertheless, with this proposed resolution we'd have no wording regarding `ios_base::app`. Currently the only statements about `app` in the Standard are just in two tables:

- Table 125 — "`openmode` effects" says that the effect of `app` is "seek to end before each write"
- Table 132 — "File open modes" says that the stdio equivalent for `app` is `"a"`

Indeed we seem to have different behavior currently in respect to `app`: For

>     stringstream s2(ios_base::out|ios_base::in|ios_base::app);
>     s2.str("s2 hello");
>     s1 << "more";

- Visual C++ 10 does overwrite (=> `"moreello"`)
- G++ 4.5 does append (=> `"s2 hellomore"`)

BTW, for fstreams, both implementations append when `app` is set: If `f2.txt` has contents `"xy"`,

>     fstream f2("f2.txt",ios_base::out|ios_base::in|ios_base::app);
>     f1 << "more";

appends `"more"` so that the contents is `"xymore"`.

So IMO `app` should set the write pointer to the end so that each writing appends.

I don't know whether what the standard says is enough. You can argue the statement in Table 125 clearly states that such a buffer should always append, which of course also applies to `str()` of stringbuffer.

Nevertheless, it doesn't hurt IMO if we clarify the behavior of `str()` here in respect to `app`.

[2011-03-10: P.J.Plauger comments:]

I think we should say nothing special about `app` at construction time (thus leaving the write pointer at the beginning of the buffer). Leave implementers wiggle room to ensure subsequent append writes as they see fit, but don't change existing rules for initial seek position.

[Madrid meeting: It was observed that a different issue should be opened that clarifies the meaning of `app` for `stringstream`]

Proposed resolution:

Change 31.8.2.4 [stringbuf.members] p. 3 as indicated:

>     void str(const basic_string<charT,traits,Allocator>& s);

> > 2 Effects: Copies the content of `s` into the `basic_stringbuf` underlying character sequence and initializes the input and output sequences according to `mode`.

> > 3 Postconditions: If `mode & ios_base::out` is true, `pbase()` points to the first underlying character and `epptr() >= pbase() + s.size()` holds; in addition, if `mode & ios_base::inios_base::ate` is true, `pptr() == pbase() + s.data()s.size()` holds, otherwise `pptr() == pbase()` is true. If `mode & ios_base::in` is true, `eback()` points to the first underlying character, and both `gptr() == eback() and egptr() == eback() + s.size()` hold.