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.

### 835. Tying two streams together (correction to DR 581)

Section: 31.5.4.3 [basic.ios.members] Status: C++11 Submitter: Martin Sebor Opened: 2008-05-17 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [basic.ios.members].

View all issues with C++11 status.

Discussion:

The fix for issue 581, now integrated into the working paper, overlooks a couple of minor problems.

First, being an unformatted function once again, `flush()` 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 `flush()` on the other tied stream(s) and vice versa, ad infinitum. The program below demonstrates the problem.

Second, as Bo Persson notes in his comp.lang.c++.moderated post, for streams with the `unitbuf` flag set such as `std::stderr`, the destructor of the sentry object will again call `flush()`. This seems to create an infinite recursion for `std::cerr << std::flush;`

>     #include <iostream>

>     int main ()
>     {
>        std::cout.tie (&std::cerr);
>        std::cerr.tie (&std::cout);
>        std::cout << "cout\n";
>        std::cerr << "cerr\n";
>     }

[ Batavia (2009-05): ]

> We agree with the proposed resolution. Move to Review.

[ 2009-05-26 Daniel adds: ]

> 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 `pubsync()` should be called, but when in this scenario `os.rdbuf()` returns 0.

> This case is explicitly handled in `flush()` and needs to be taken care of. My suggested fix is:

> > If `((os.flags() & ios_base::unitbuf) && !uncaught_exception()` `&& os.rdbuf() != 0`) is true, calls `os.flush()` `os.rdbuf()->pubsync()`.

> Two secondary questions are:

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

[ 2009-07 Frankfurt: ]

> Daniel volunteered to modify the proposed resolution to address his two questions.

> Move back to Open.

[ 2009-07-26 Daniel provided wording. Moved to Review. ]

[ 2009-10-13 Daniel adds: ]

> This proposed wording is written to match the outcome of 397.

[ 2009 Santa Cruz: ]

> Move to Open. Martin to propose updated wording that will also resolve issue 397 consistently.

[ 2010-02-15 Martin provided wording. ]

[ 2010 Pittsburgh: ]

> Moved to Ready for Pittsburgh.

Proposed resolution:

1. Just before 31.5.4.3 [basic.ios.members] p. 2 insert a new paragraph:

   > Requires: If `(tiestr != 0)` is `true`, `tiestr` must not be reachable by traversing the linked list of tied stream objects starting from `tiestr->tie()`.

2. Change [ostream::sentry] p. 4 as indicated:

   > If `((os.flags() & ios_base::unitbuf) && !uncaught_exception() && os.good())` is `true`, calls `os.flush()` `os.rdbuf()->pubsync()`. If that function returns -1 sets `badbit` in `os.rdstate()` without propagating an exception.

3. Add after [ostream::sentry] p17, the following paragraph:

   > Throws: Nothing.