basic_ios::set_rdbuf
may break class invariantsSection: 31.5.4.3 [basic.ios.members] Status: C++11 Submitter: Daniel Krügler Opened: 2009-07-28 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 protected member function set_rdbuf
had been added during the
process of adding move and swap semantics to IO classes. A relevant
property of this function is described by it's effects in
31.5.4.3 [basic.ios.members]/19:
Effects: Associates the
basic_streambuf
object pointed to by sb with this stream without callingclear()
.
This means that implementors of or those who derive from existing IO classes
could cause an internal state where the stream buffer could be 0, but the
IO class has the state good()
. This would break several currently existing
implementations which rely on the fact that setting a stream buffer via the
currently only ways, i.e. either by calling
void init(basic_streambuf<charT,traits>* sb);
or by calling
basic_streambuf<charT,traits>* rdbuf(basic_streambuf<charT,traits>* sb);
to set rdstate()
to badbit
, if the buffer is 0. This has the effect that many
internal functions can simply check rdstate()
instead of rdbuf()
for being 0.
I therefore suggest that a requirement is added for callers of set_rdbuf
to
set a non-0 value.
[ 2009-10 Santa Cruz: ]
Moved to Open. Martin volunteers to provide new wording, where
set_rdbuf()
sets thebadbit
but does not cause an exception to be thrown like a call toclear()
would.
[ 2009-10-20 Martin provides wording: ]
Change 31.5.4.3 [basic.ios.members] around p. 19 as indicated:
void set_rdbuf(basic_streambuf<charT, traits>* sb);
Effects: Associates thebasic_streambuf
object pointed to bysb
with this stream without callingclear()
. Postconditions:rdbuf() == sb
.Effects: As if:
iostate state = rdstate(); try { rdbuf(sb); } catch(ios_base::failure) { if (0 == (state & ios_base::badbit)) unsetf(badbit); }Throws: Nothing.
Rationale:
We need to be able to call set_rdbuf()
on stream objects
for which (rdbuf() == 0
) holds without causing ios_base::failure
to
be thrown. We also don't want badbit
to be set as a result of
setting rdbuf()
to 0 if it wasn't set before the call. This changed
Effects clause maintains the current behavior (as of N2914) without
requiring that sb
be non-null.
[ Post-Rapperswil ]
Several reviewers and the submitter believe that the best solution would be to add a pre-condition that the buffer shall not be a null pointer value.
Moved to Tentatively Ready with revised wording provided by Daniel after 5 positive votes on c++std-lib.
[ Adopted at 2010-11 Batavia ]
Proposed resolution:
void set_rdbuf(basic_streambuf<charT, traits>* sb);?? Requires:
23 Effects: Associates thesb != nullptr
.basic_streambuf
object pointed to bysb
with this stream without callingclear()
.24 Postconditions:
rdbuf() == sb
.25 Throws: Nothing.
Rationale:
We believe that setting a nullptr
stream buffer can be prevented.