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.

### 1183. `basic_ios::set_rdbuf` may break class invariants

Section: 29.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 29.5.4.3 [basic.ios.members]/19:

> Effects: Associates the `basic_streambuf` object pointed to by sb with this stream without calling `clear()`.

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 the `badbit` but does not cause an exception to be thrown like a call to `clear()` would.

[ 2009-10-20 Martin provides wording: ]

Change 29.5.4.3 [basic.ios.members] around p. 19 as indicated:

>     void set_rdbuf(basic_streambuf<charT, traits>* sb);

> > Effects: Associates the `basic_streambuf` object pointed to by `sb` with this stream without calling `clear()`. 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:

1. Add a new pre-condition just before 27.5.4.2 [basic.ios.members]/23 as indicated:

   >     void set_rdbuf(basic_streambuf<charT, traits>* sb);

   > > ?? Requires: `sb != nullptr`.

   > > 23 Effects: Associates the `basic_streambuf` object pointed to by `sb` with this stream without calling `clear()`.

   > > 24 Postconditions: `rdbuf() == sb`.

   > > 25 Throws: Nothing.

Rationale:

We believe that setting a `nullptr` stream buffer can be prevented.