<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 911: I&#47;O streams and move&#47;swap semantic</title>
<meta property="og:title" content="Issue 911: I&#47;O streams and move&#47;swap semantic">
<meta property="og:description" content="C++ library issue. Status: C++11">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue911.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++11">C++11</a> status.</em></p>
<h3 id="911"><a href="lwg-defects.html#911">911</a>. I&#47;O streams and <code>move&#47;swap</code> semantic</h3>
<p><b>Section:</b> 31.7.5 <a href="https://wg21.link/input.streams">[input.streams]</a>, 31.7.6 <a href="https://wg21.link/output.streams">[output.streams]</a> <b>Status:</b> <a href="lwg-active.html#C++11">C++11</a>
 <b>Submitter:</b> Alberto Ganesh Barbati <b>Opened:</b> 2008-09-29 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++11">C++11</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Class template <code>basic_istream</code>, <code>basic_ostream</code> and <code>basic_iostream</code>
implements public move constructors, move assignment operators and <code>swap</code>
method and free functions. This might induce both the user and the
compiler to think that those types are <code>MoveConstructible</code>, <code>MoveAssignable</code>
and <code>Swappable</code>. However, those class templates fail to fulfill the user
expectations. For example:
</p>

<blockquote><pre>
std::ostream os(std::ofstream("file.txt"));
assert(os.rdbuf() == 0); // buffer object is not moved to os, file.txt has been closed

std::vector&lt;std::ostream&gt; v;
v.push_back(std::ofstream("file.txt"));
v.reserve(100); // causes reallocation
assert(v[0].rdbuf() == 0); // file.txt has been closed!

std::ostream&amp;&amp; os1 = std::ofstream("file1.txt");
os1 = std::ofstream("file2.txt");
os1 &lt;&lt; "hello, world"; // still writes to file1.txt, not to file2.txt!

std::ostream&amp;&amp; os1 = std::ofstream("file1.txt");
std::ostream&amp;&amp; os2 = std::ofstream("file2.txt");
std::swap(os1, os2);
os1 &lt;&lt; "hello, world"; // writes to file1.txt, not to file2.txt!
</pre></blockquote>

<p>
This is because the move constructor, the move assignment operator and
<code>swap</code> are all implemented through calls to <code>std::basic_ios</code> member
functions <code>move()</code> and <code>swap()</code> that do not move nor swap the controlled
stream buffers. That can't happen because the stream buffers may have
different types.
</p>

<p>
Notice that for <code>basic_streambuf</code>, the member function <code>swap()</code> is
protected. I believe that is correct and all of <code>basic_istream</code>,
<code>basic_ostream</code>, <code>basic_iostream</code> should do the same as the move ctor, move
assignment operator and swap member function are needed by the derived
<code>fstream</code>s and <code>stringstream</code>s template. The free swap functions for
<code>basic_(i|o|io)stream</code> templates should be removed for the same reason.
</p>

<p><i>[
Batavia (2009-05):
]</i></p>

<blockquote>
<p>
We note that the rvalue swap functions have already been removed.
</p>
<p>
Bill is unsure about making the affected functions protected;
he believes they may need to be public.
</p>
<p>
We are also unsure about removing the lvalue swap functions as proposed.
</p>
<p>
Move to Open.
</p>
</blockquote>

<p><i>[
2009-07 Frankfurt:
]</i></p>


<blockquote>
<p>
It's not clear that the use case is compelling.
</p>
<p>
Howard: This needs to be implemented and tested.
</p>
</blockquote>

<p><i>[
2009-07-26 Howard adds:
]</i></p>


<blockquote>
<p>
I started out thinking I would recommend NAD for this one.  I've turned around
to agree with the proposed resolution (which I've updated to the current draft).
I did not fully understand Ganesh's rationale, and attempt to describe my
improved understanding below.
</p>

<p>
The move constructor, move assignment operator, and swap function are different
for <code>basic_istream</code>, <code>basic_ostream</code> and <code>basic_iostream</code>
than other classes.  A timely conversation with Daniel reminded me of this long
forgotten fact.  These members are sufficiently different that they would be
extremely confusing to use in general, but they are very much needed for derived
clients.
</p>

<ul>
<li>
The move constructor moves everything but the <code>rdbuf</code> pointer.
</li>
<li>
The move assignment operator moves everything but the <code>rdbuf</code> pointer.
</li>
<li>
The swap function swaps everything but the <code>rdbuf</code> pointer.
</li>
</ul>

<p>
The reason for this behavior is that for the std-derived classes (stringstreams,
filestreams), the <code>rdbuf</code> pointer points back into the class itself
(self referencing).  It can't be swapped or moved.  But this fact isn't born out
at the <code>stream</code> level.  Rather it is born out at the <code>fstream</code>/<code>sstream</code>
level.  And the lower levels just need to deal with that fact by not messing around
with the <code>rdbuf</code> pointer which is stored down at the lower levels.
</p>

<p>
In a nutshell, it is very confusing for all of those who are not so intimately
related with streams that they've implemented them.  And it is even fairly
confusing for some of those who have (including myself).  I do not think it is
safe to swap or move <code>istreams</code> or <code>ostreams</code> because this will
(by necessary design) separate stream state from streambuffer state.  Derived
classes (such as <code>fstream</code> and <code>stringstream</code> must be used to
keep the stream state and stream buffer consistently packaged as one unit during
a move or swap.
</p>

<p>
I've implemented this proposal and am living with it day to day.
</p>

</blockquote>

<p><i>[
2009 Santa Cruz:
]</i></p>


<blockquote><p>
Leave Open.  Pablo expected to propose alternative wording which would rename
move construction, move assignment and swap, and may or may not make them
protected.  This will impact issue <a href="lwg-defects.html#900" title="Stream move-assignment (Status: C++11)">900</a><sup><a href="https://cplusplus.github.io/LWG/issue900" title="Latest snapshot">(i)</a></sup>.
</p></blockquote>

<p><i>[
2010 Pittsburgh:
]</i></p>


<blockquote><p>
Moved to Ready for Pittsburgh.
</p></blockquote>



<p id="res-911"><b>Proposed resolution:</b></p>
<p>
31.7.5.2 <a href="https://wg21.link/istream">[istream]</a>: make the following member functions protected:
</p>

<blockquote><pre>
basic_istream(basic_istream&amp;&amp;  rhs);
basic_istream&amp;  operator=(basic_istream&amp;&amp;  rhs);
void  swap(basic_istream&amp;  rhs);
</pre></blockquote>

<p>
Ditto: remove the swap free function signature
</p>

<blockquote><pre>
<del>// swap: 
template &lt;class charT, class traits&gt; 
  void swap(basic_istream&lt;charT, traits&gt;&amp; x, basic_istream&lt;charT, traits&gt;&amp; y);</del>
</pre></blockquote>

<p>
31.7.5.2.3 <a href="https://wg21.link/istream.assign">[istream.assign]</a>: remove paragraph 4
</p>

<blockquote><pre>
<del>template &lt;class charT, class traits&gt; 
  void swap(basic_istream&lt;charT, traits&gt;&amp; x, basic_istream&lt;charT, traits&gt;&amp; y);</del>
</pre>
<blockquote><p>
<del><i>Effects:</i> <code>x.swap(y)</code>.</del>
</p></blockquote>
</blockquote>

<p>
31.7.5.7 <a href="https://wg21.link/iostreamclass">[iostreamclass]</a>: make the following member function protected:
</p>

<blockquote><pre>
basic_iostream(basic_iostream&amp;&amp;  rhs);
basic_iostream&amp;  operator=(basic_iostream&amp;&amp;  rhs);
void  swap(basic_iostream&amp;  rhs);
</pre></blockquote>

<p>
Ditto: remove the swap free function signature
</p>

<blockquote><pre>
<del>template &lt;class charT, class traits&gt; 
  void swap(basic_iostream&lt;charT, traits&gt;&amp; x, basic_iostream&lt;charT, traits&gt;&amp; y);</del>
</pre></blockquote>

<p>
31.7.5.7.4 <a href="https://wg21.link/iostream.assign">[iostream.assign]</a>: remove paragraph 3
</p>

<blockquote><pre>
<del>template &lt;class charT, class traits&gt; 
  void swap(basic_iostream&lt;charT, traits&gt;&amp; x, basic_iostream&lt;charT, traits&gt;&amp; y);</del>
</pre>
<blockquote><p>
<del><i>Effects:</i> <code>x.swap(y)</code>.</del>
</p></blockquote>
</blockquote>

<p>
31.7.6.2 <a href="https://wg21.link/ostream">[ostream]</a>: make the following member function protected:
</p>

<blockquote><pre>
basic_ostream(basic_ostream&amp;&amp;  rhs);
basic_ostream&amp;  operator=(basic_ostream&amp;&amp;  rhs);
void  swap(basic_ostream&amp;  rhs);
</pre></blockquote>

<p>
Ditto: remove the swap free function signature
</p>

<blockquote><pre>
<del>// swap: 
template &lt;class charT, class traits&gt; 
  void swap(basic_ostream&lt;charT, traits&gt;&amp; x, basic_ostream&lt;charT, traits&gt;&amp; y);</del>
</pre></blockquote>

<p>
31.7.6.2.3 <a href="https://wg21.link/ostream.assign">[ostream.assign]</a>: remove paragraph 4 
</p>

<blockquote><pre>
<del>template &lt;class charT, class traits&gt; 
  void swap(basic_ostream&lt;charT, traits&gt;&amp; x, basic_ostream&lt;charT, traits&gt;&amp; y);</del>
</pre>
<blockquote><p>
<del><i>Effects:</i> <code>x.swap(y)</code>.</del>
</p></blockquote>
</blockquote>






</body>
</html>
