Title
Tying two streams together (correction to DR 581)
Status
c++11
Section
[basic.ios.members]
Submitter
Martin Sebor

Created on 2008-05-17.00:00:00 last changed 161 months ago

Messages

Date: 2011-04-28.21:34:33

Proposed resolution:

  1. Just before [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.

Date: 2010-10-21.18:28:33

[ 2010 Pittsburgh: ]

Moved to Ready for Pittsburgh.

Date: 2010-02-15.00:00:00

[ 2010-02-15 Martin provided wording. ]

Date: 2010-10-21.18:28:33

[ 2009 Santa Cruz: ]

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

Date: 2009-10-13.00:00:00

[ 2009-10-13 Daniel adds: ]

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

Date: 2009-07-26.00:00:00

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

Date: 2010-10-21.18:28:33

[ 2009-07 Frankfurt: ]

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

Move back to Open.

Date: 2009-05-26.00:00:00

[ 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)?
Date: 2010-10-21.18:28:33

[ Batavia (2009-05): ]

We agree with the proposed resolution. Move to Review.

Date: 2008-05-17.00:00:00

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";
} 
History
Date User Action Args
2011-08-23 20:07:26adminsetstatus: wp -> c++11
2010-10-21 18:28:33adminsetmessages: + msg3996
2010-10-21 18:28:33adminsetmessages: + msg3995
2010-10-21 18:28:33adminsetmessages: + msg3994
2010-10-21 18:28:33adminsetmessages: + msg3993
2010-10-21 18:28:33adminsetmessages: + msg3992
2010-10-21 18:28:33adminsetmessages: + msg3991
2010-10-21 18:28:33adminsetmessages: + msg3990
2010-10-21 18:28:33adminsetmessages: + msg3989
2010-10-21 18:28:33adminsetmessages: + msg3988
2008-05-17 00:00:00admincreate