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?
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.
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 thati/o_stream::swap
is also protected and with no namespace-scope variant. And their spec is to call the base classswap
and then swap any local data (such as thegcount
inistream
).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 memberstring/file buffer
(therdbuf
) and the base class. Theswap
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'sstreambuf
(basic_filebuf
orbasic_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'sswap
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 thei/ostream
level. It was a very good call on his part that I had completely missed with my first design.