C++11 §27.5.4.2/21:
void swap(basic_ios& rhs);
Effects: The states of
*this
andrhs
shall be exchanged, except thatrdbuf()
shall return the same value as it returned before the function call, andrhs.rdbuf()
shall return the same value as it returned before the function call.
What is this partial swapping useful for?
Can it cause trouble?
You can blame me for this one. The committee has tried to change (twice I think), but each time the solution ended up breaking things.
Swap and move semantics was retrofitted onto our I/O system a decade after it was designed. And it wasn't a perfectly clean fit.
Note that basic_ios::swap
is a protected member function and there is no namespace-scope variant. Thus this can only be called from a derived class (typically istream/ostream). Note that i/o_stream::swap
is also protected and with no namespace-scope variant. And their spec is to call the base class swap
and then swap any local data (such as the gcount
in istream
).
Finally up at the string/filestream
level you get what you would consider a "normal" swap
: public member and namespace-scope variants. At this level you've got a data member string/file buffer
(the rdbuf
) and the base class. The swap
at this level simply swaps the base and data members.
The complicating characteristic of all this is that the rdbuf()
down in the base class is actually a self-referencing pointer to the derived class's streambuf
(basic_filebuf
or basic_stringbuf
) and that is why you don't want the base class to swap these self-referencing pointers.
This makes the base swap
weird, but everyone is protected from it except the derived clients. And the code for the derived client's swap
is subsequently deceptively simple looking. And at the derived level, swap
is made public and behaves in the manner that public clients expect it to.
A similar dance is made for move construction and move assignment. Move construction is further complicated by the fact that the base class is a virtual base, and thus its constructor is not called by the most directly derived class.
It was fun. It looks weird. But it ultimately works. ;-)
Slight Correction:
Alberto Ganesh Barbati is responsible for protecting swap
at the i/ostream
level. It was a very good call on his part that I had completely missed with my first design.
I only have one speculative answer...
If the author assumed that a stream may use an internal buffer (for example a char buffer[50]
data member), then this provision is necessary as obviously the content of the buffers may be swapped, but their address will remain unchanged.
I do not know whether it is actually allowed or not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With