﻿<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
<title>Generating move operations (elaborating on Core 1402)</title>
<meta name="date" content="2012-09-21" />
<meta name="authors" content="Ville Voutilainen &lt;ville.voutilainen&#64;gmail.com&gt;" />
<style type="text/css">

/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.

See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/

/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
  border: 0 }

table.borderless td, table.borderless th {
  /* Override padding for "table.docutils td" with "! important".
     The right padding separates the table cells. */
  padding: 0 0.5em 0 0 ! important }

.first {
  /* Override more specific margin styles with "! important". */
  margin-top: 0 ! important }

.last, .with-subtitle {
  margin-bottom: 0 ! important }

.hidden {
  display: none }

a.toc-backref {
  text-decoration: none ;
  color: black }

blockquote.epigraph {
  margin: 2em 5em ; }

dl.docutils dd {
  margin-bottom: 0.5em }

/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
  font-weight: bold }
*/

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

/* Uncomment (and remove this text!) to get reduced vertical space in
   compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
  margin-bottom: 0.5em }

div.compound .compound-last, div.compound .compound-middle {
  margin-top: 0.5em }
*/

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em ;
  margin-right: 2em }

div.footer, div.header {
  clear: both;
  font-size: smaller }

div.line-block {
  display: block ;
  margin-top: 1em ;
  margin-bottom: 1em }

div.line-block div.line-block {
  margin-top: 0 ;
  margin-bottom: 0 ;
  margin-left: 1.5em }

div.sidebar {
  margin: 0 0 0.5em 1em ;
  border: medium outset ;
  padding: 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
  margin-top: 0.4em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

hr.docutils {
  width: 75% }

img.align-left, .figure.align-left{
  clear: left ;
  float: left ;
  margin-right: 1em }

img.align-right, .figure.align-right {
  clear: right ;
  float: right ;
  margin-left: 1em }

.align-left {
  text-align: left }

.align-center {
  clear: both ;
  text-align: center }

.align-right {
  text-align: right }

/* reset inner alignment in figures */
div.align-right {
  text-align: left }

/* div.align-center * { */
/*   text-align: left } */

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font: inherit }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em }

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

span.section-subtitle {
  /* font-size relative to parent (h1..h6 element) */
  font-size: 80% }

table.citation {
  border-left: solid 1px gray;
  margin-left: 1px }

table.docinfo {
  margin: 2em 4em }

table.docutils {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.footnote {
  border-left: solid 1px black;
  margin-left: 1px }

table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

table.docutils th.field-name, table.docinfo th.docinfo-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap ;
  padding-left: 0 }

h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
  font-size: 100% }

ul.auto-toc {
  list-style-type: none }

</style>
</head>
<body>
<div class="document" id="generating-move-operations-elaborating-on-core-1402">
<h1 class="title">Generating move operations (elaborating on Core 1402)</h1>
<table class="docinfo" frame="void" rules="none">
<col class="docinfo-name" />
<col class="docinfo-content" />
<tbody valign="top">
<tr><th class="docinfo-name">Date:</th>
<td>2012-09-21</td></tr>
<tr><th class="docinfo-name">Version:</th>
<td>N3401=12-0091</td></tr>
<tr><th class="docinfo-name">Authors:</th>
<td>Ville Voutilainen &lt;<a class="reference external" href="mailto:ville.voutilainen&#64;gmail.com">ville.voutilainen&#64;gmail.com</a>&gt;</td></tr>
</tbody>
</table>
<div class="abstract topic">
<p class="topic-title first">Abstract</p>
<p>As Core 1402 states, C++11 is excessively strict
about deleting move operations if subobjects have no
move operation or the copy operation is non-trivial.
Several people have suggested that Core 1402 doesn't
go far enough; this paper provides an analysis of
the proposed options. The options are, briefly,
1) status quo 2) Core 1402 3) suppress also
explicitly defaulted move operations (Merrill)
4) don't suppress nor delete move operations
if a moving expression for subobjects is valid
(Hinnant). This paper suggests selecting option 4.</p>
<p>N3201 &quot;Moving right along&quot;
by Stroustrup (see <a class="reference external" href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2010/n3201.pdf">http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2010/n3201.pdf</a>) is the earlier paper on the subject.</p>
</div>
<p>I wish to thank Daniel Krügler for reporting Core 1402 and
providing a solution for it, and Jason Merrill,
Howard Hinnant and Dave Abrahams for providing elaborated solutions and
input for this paper. This paper tries to capture what
Merrill and Hinnant have proposed on the core reflector.</p>
<div class="section" id="status-quo">
<h1>Status quo</h1>
<p>Core 1402 explains the problem with the status quo:</p>
<pre class="literal-block">
template&lt;typename T&gt;
 struct wrap {
   wrap() = default;
#ifdef USE_DEFAULTED_MOVE
   wrap(wrap&amp;&amp;) = default;
#else
   wrap(wrap&amp;&amp; w) : t(static_cast&lt;T&amp;&amp;&gt;(w.t)) { }
#endif
   wrap(const wrap&amp;) = default;
   T t;
 };
 struct S {
   S(){}
   S(const S&amp;){}
   S(S&amp;&amp;){}
 };
 typedef wrap&lt;const S&gt; W;
 W get() { return W(); }  // Error, if USE_DEFAULTED_MOVE is defined, else OK
</pre>
<p>In this example the defaulted move constructor of wrap is selected by overload resolution, but this move-constructor is deleted, because S has no trivial copy-constructor.</p>
<p>Merrill stated the following about status quo:</p>
<pre class="literal-block">
Any non-static data member or base with no move constructor and a
non-trivial copy constructor causes an explicitly defaulted declaration
to be deleted.

One problem with this is that it is badly specified: the rest of 12.8 was
fixed to talk about the function chosen by overload resolution rather than
what a type &quot;has&quot;, but this part was not.

The status quo makes std::map unusable, because map wants to create a
pair&lt;const Key, Val&gt; with a const first type, and a const member cannot be moved.
So the move constructor is deleted, so trying to initialize one of these pairs
from an rvalue is ill-formed.  I don't think we can stick with the status quo.
</pre>
</div>
<div class="section" id="core-1402">
<h1>Core 1402</h1>
<p>Merrill stated the following about Core 1402:</p>
<pre class="literal-block">
The current proposed wording for 1402 changes the existing restrictions
from causing the move to be deleted to instead only suppressing the implicit
declaration.  So the pair&lt;const Key, Val&gt; move constructor is defined,
copies the first member, and moves the second member.

The current proposed wording still suffers from the specification issue above.
</pre>
</div>
<div class="section" id="suppressing-both-implicitly-and-explicitly-defaulted-moves">
<h1>Suppressing both implicitly and explicitly defaulted moves</h1>
<p>Merrill stated the following:</p>
<pre class="literal-block">
I'm now wondering if we want to deal with this by treating =default
declarations of move ops the same as implicit declarations: if they
would cause the function to be declared as deleted, instead just
suppress the declaration.
</pre>
</div>
<div class="section" id="allowing-generated-move-operations-even-for-non-movable-or-non-trivially-copyable-subobjects">
<h1>Allowing generated move operations even for non-movable or non-trivially-copyable subobjects</h1>
<p>Hinnant proposed the following:</p>
<pre class="literal-block">
Also consider:  The LWG decided long ago that it is ok for a
move member to throw an exception.  We know how to deal with that and already do.

For simplicity and consistency I would like to see:

1.  An implicit move member behave the same way as an explicitly defaulted one
(and vice-versa).  I believe this invariant is already true for the other
special members.

2.  If for all bases and non-static data members, if the initialization

        X(X&amp;&amp; x) : a_(std::move(x.a_))

is well formed, then the defaulted definition should not be deleted.
I.e. the rules should be expression-based, and should not depend upon what
constructor of a_ actually gets called (a throwing copy constructor is fine,
it will produce a valid throwing move constructor for X).
</pre>
</div>
<div class="section" id="comparison-of-the-options">
<h1>Comparison of the options</h1>
<p>Merrill made the following summary:</p>
<p>All the options concern certain restrictions on defaulted move ctor/op=.</p>
<ul class="simple">
<li>If the move would involve a non-trivial copy ctor/op=, or</li>
<li>For move op=, if a virtual base has a non-trivial move op=.</li>
</ul>
<p>If one of these conditions are found, what happens to implicit/explicitly defaulted move ctor/op=?</p>
<table border="1" class="docutils">
<colgroup>
<col width="45%" />
<col width="28%" />
<col width="28%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Option</th>
<th class="head">Implicit</th>
<th class="head">Explicit</th>
</tr>
</thead>
<tbody valign="top">
<tr><td><ol class="first last arabic simple">
<li>Status quo</li>
</ol>
</td>
<td>suppress</td>
<td>delete</td>
</tr>
<tr><td><ol class="first last arabic simple" start="2">
<li>Core 1402</li>
</ol>
</td>
<td>suppress</td>
<td>ok</td>
</tr>
<tr><td><ol class="first last arabic simple" start="3">
<li>Merrill</li>
</ol>
</td>
<td>suppress</td>
<td>suppress</td>
</tr>
<tr><td><ol class="first last arabic simple" start="4">
<li>Hinnant</li>
</ol>
</td>
<td>ok</td>
<td>ok</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="examples">
<h1>Examples</h1>
<p>As shown in Core 1402, status quo will lead to a deleted
function being chosen by overload resolution if a subobject
has no move operation and has a non-trivial copy operation.</p>
<p>A different example is</p>
<pre class="literal-block">
struct Y {
       Y() = default;
       Y(const Y&amp;) {} /* non-trivial copy, move suppressed */
};

struct X {
       const Y a;
       string b;
       X() : a() {}
       X(X&amp;&amp;) = default; /* would work without this... */
protected:
       X(const X&amp;) = default; /* ...but we need it if we declare a copy operation */
};

X foo() { return X(); }
void foo2(X&amp;&amp; x);

int main()
{
        foo2(foo()); /* can't move X, but chosen by overload resolution */
        X x2 = foo(); /* same here */
}
</pre>
<p>With Core 1402, this example works, because the defaulted
move operation is not deleted, and it'll copy the const Y
member and move the string member.</p>
<p>The apparent problem with Core 1402 is that it treats
implicitly and explicitly defaulted move operations
differently. Explicitly defaulted move operations
aren't suppressed even if subobjects have no
move and no trivial copy operations, whereas implicitly
defaulted move operations are suppressed in those cases.
This leads into a situation where, for a class that
has a movable and copyable subobject, and a non-trivial
copy-only subobject, everything gets copied, but when the move
operation is defaulted, the movable and copyable subobject
can be moved. Example:</p>
<pre class="literal-block">
struct Y {
       Y() = default;
       Y(const Y&amp;) {}
};
struct Z {
       Z()=default;
       Z(const Z&amp;) {}
       Z(Z&amp;&amp;) {};
};
struct X {
       const Y a;
       Z b;
       X() : a() {}
};

X foo() {return X();} /* this will copy both X::b and X::a */
void foo2(X&amp;&amp; x) {}

int main()
{
       foo2(foo());
}
</pre>
<p>If X has a defaulted move, the foo2(foo()); will not copy X::b, but will
copy X::a.</p>
<p>Merrill proposes that both implicitly and explicitly
defaulted move operations should be suppressed if
there's a subobject with no move operation and no
trivial copy operation. This makes the implicitly
and explicitly defaulted cases do the same thing,
which is fallback on copying.</p>
<p>Hinnant points out that any kind of suppression
is problematic, because if the move operation
is completely suppressed, copy operations will
not invoke move operations for subobjects. His
example is</p>
<pre class="literal-block">
struct B {
       B();
       B(const B&amp;);
};

struct A {
       B b;
       std::unique_ptr&lt;int&gt; ptr;
};

A make()
{
      return A();
}
</pre>
<p>Hinnant elaborates:</p>
<pre class="literal-block">
If we either delete *or* suppress A's move constructor in this example,
the above code becomes invalid because the return from make() will have
to fall back on A's implicit copy constructor which is deleted because
of the move-only unique_ptr member.
</pre>
</div>
<div class="section" id="orthogonal-aspect-does-noexcept-or-triviality-matter">
<h1>Orthogonal(?) aspect: does noexcept or triviality matter?</h1>
<p>Hinnant stated the following:</p>
<pre class="literal-block">
The LWG decided long ago that it is ok for a move member to
throw an exception. We know how to deal with that and already do.
The rules should be expression-based, and should not depend
upon what constructor of a_ actually gets called (a throwing
copy constructor is fine, it will produce a valid throwing
move constructor for X).
</pre>
<p>The status quo rules apparently avoid deleting a move operation
if a subobject has no move operation but has a trivial copy
operation for three reasons: 1) a trivial copy operation will
not throw 2) a trivial copy operation is efficient 3) there's
already a large amount of examples which lead people to
believe that the expression X(X&amp;&amp; x) : a_(std::move(x.a_))
is safe, if they choose to write it explicitly. To deal with
a throwing move, the safe alternative would actually be
X(X&amp;&amp; x) : a_(std::move_if_noexcept(x.a_)).</p>
<p>It's questionable whether this aspect is truly orthogonal;
if we choose to delete or suppress move operations because
a copy operation is available, but is non-trivial or throwing,
we end up in problematic situations again. Generic wrappers
will end up with either
1) deleted moves being resolved to, or
2) copy operations doing just copies, and failing when there's
a suitable mixture of moves and copies to be done, if
there would be a suitable move but a deleted copy.</p>
</div>
<div class="section" id="invariants">
<h1>Invariants</h1>
<p>Abrahams asked whether the solutions proposed can lead to
more cases where invariants can be broken. This seems to
be the case in an example such as the following:</p>
<pre class="literal-block">
struct X
{
  X(const X&amp; other) : a(other.a) {} // let's make the copy non-trivial, and the type non-movable in c++11
};

class Y
{
 string a;
 X b;
 void invariant() {assert(!a.empty);}
 // we don't want a destructor, we don't care about checking the invariant in it
 // we don't declare a copy constructor, we think the invariant will hold before and after copying
public:
 Y() : a(&quot;foo&quot;) {} // establish an invariant
 f() {invariant();} // and check it
};
</pre>
<p>The status quo rules would suppress move operations for Y,
as would Merrill's solution. Hinnant's solution will generate
move operations that can break the invariant. For cases where
an object of type Y is returned from a function, that doesn't
cause problems since the default destructor will not trigger
the invariant check, and a user-declared destructor would
suppress the move operations. For cases where a move from
an lvalue happens, the invariant check can be triggered to
assert from outside of class Y.</p>
</div>
<div class="section" id="conclusion">
<h1>Conclusion</h1>
<p>It seems that whenever we suppress or delete a move operation,
we end up in a situation where seemingly valid code ends
up ill-formed due to the deleted move operation
being resolved to, or can end up ill-formed due to resolving to
a possibly deleted copy operation even if a suitable move would
be available. Therefore it would
seem reasonable to strive for a solution that minimizes
deleting or suppressing moves. Hinnant's solution seems
to do that. It also has the benefit of treating implicitly
and explicitly defaulted move operations the same way,
but is superior to Merrill's solution because it doesn't
suppress as many moves and does not lead to ill-formed
code in the case of a mixture of moves and copies. It also
solves the possibly orthogonal issue about whether noexcept
or triviality matter, by simply saying they don't receive
any special treatment. Finally, despite the invariant
concerns mentioned, this paper still proposes Hinnant's
solution, because the rule uniformity and teachability
is considered to trump the theoretically rare case of
breaking invariants.</p>
</div>
<div class="section" id="wording">
<h1>Wording?</h1>
<p>Due to lack of time, there's no wording draft at this point.</p>
</div>
</div>
</body>
</html>
