| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> |
| <title>Implicit Move when returning a local object</title> |
| <link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css"> |
| <meta name="generator" content="DocBook XSL Stylesheets V1.78.1"> |
| <link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset"> |
| <link rel="up" href="../move.html" title="Chapter 19. Boost.Move"> |
| <link rel="prev" href="construct_forwarding.html" title="Constructor Forwarding"> |
| <link rel="next" href="move_iterator.html" title="Move iterators"> |
| </head> |
| <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> |
| <table cellpadding="2" width="100%"><tr> |
| <td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td> |
| <td align="center"><a href="../../../index.html">Home</a></td> |
| <td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td> |
| <td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> |
| <td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> |
| <td align="center"><a href="../../../more/index.htm">More</a></td> |
| </tr></table> |
| <hr> |
| <div class="spirit-nav"> |
| <a accesskey="p" href="construct_forwarding.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../move.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="move_iterator.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
| <a name="move.move_return"></a><a class="link" href="move_return.html" title="Implicit Move when returning a local object">Implicit Move when returning a local |
| object</a> |
| </h2></div></div></div> |
| <p> |
| The C++ standard specifies situations where an implicit move operation is safe |
| and the compiler can use it in cases were the (Named) Return Value Optimization) |
| can't be used. The typical use case is when a function returns a named (non-temporary) |
| object by value and the following code will perfectly compile in C++11: |
| </p> |
| <pre class="programlisting"><span class="comment">//Even if movable can't be copied</span> |
| <span class="comment">//the compiler will call the move-constructor</span> |
| <span class="comment">//to generate the return value</span> |
| <span class="comment">//</span> |
| <span class="comment">//The compiler can also optimize out the move</span> |
| <span class="comment">//and directly construct the object 'm'</span> |
| <span class="identifier">movable</span> <span class="identifier">factory</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">movable</span> <span class="identifier">tmp</span><span class="special">;</span> |
| <span class="identifier">m</span> <span class="special">=</span> <span class="special">...</span> |
| <span class="comment">//(1) moved instead of copied</span> |
| <span class="keyword">return</span> <span class="identifier">tmp</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">//Initialize object</span> |
| <span class="identifier">movable</span> <span class="identifier">m</span><span class="special">(</span><span class="identifier">factory</span><span class="special">());</span> |
| </pre> |
| <p> |
| In compilers without rvalue references and some non-conforming compilers (such |
| as Visual C++ 2010/2012) the line marked with <code class="computeroutput"><span class="special">(</span><span class="number">1</span><span class="special">)</span></code> would trigger |
| a compilation error because <code class="computeroutput"><span class="identifier">movable</span></code> |
| can't be copied. Using a explicit <code class="computeroutput"><span class="special">::</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">tmp</span><span class="special">)</span></code> |
| would workaround this limitation but it would code suboptimal in C++11 compilers |
| (as the compile could not use (N)RVO to optimize-away the copy/move). |
| </p> |
| <p> |
| <span class="bold"><strong>Boost.Move</strong></span> offers an additional macro called |
| <code class="computeroutput"><a class="link" href="../BOOST_MOVE_RET.html" title="Macro BOOST_MOVE_RET">BOOST_MOVE_RET</a></code> that can be used |
| to alleviate this problem obtaining portable move-on-return semantics. Let's |
| use the previously presented movable-only <code class="computeroutput"><span class="identifier">movable</span></code> |
| class with classes <code class="computeroutput"><span class="identifier">copyable</span></code> |
| (copy-only type), <code class="computeroutput"><span class="identifier">copy_movable</span></code> |
| (can be copied and moved) and <code class="computeroutput"><span class="identifier">non_copy_movable</span></code> |
| (non-copyable and non-movable): |
| </p> |
| <p> |
| </p> |
| <pre class="programlisting"><span class="comment">//header file "copymovable.hpp"</span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">move</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| |
| <span class="comment">//A copy_movable class</span> |
| <span class="keyword">class</span> <span class="identifier">copy_movable</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_COPYABLE_AND_MOVABLE</span><span class="special">(</span><span class="identifier">copy_movable</span><span class="special">)</span> |
| <span class="keyword">int</span> <span class="identifier">value_</span><span class="special">;</span> |
| |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="identifier">copy_movable</span><span class="special">()</span> <span class="special">:</span> <span class="identifier">value_</span><span class="special">(</span><span class="number">1</span><span class="special">){}</span> |
| |
| <span class="comment">//Move constructor and assignment</span> |
| <span class="identifier">copy_movable</span><span class="special">(</span><span class="identifier">BOOST_RV_REF</span><span class="special">(</span><span class="identifier">copy_movable</span><span class="special">)</span> <span class="identifier">m</span><span class="special">)</span> |
| <span class="special">{</span> <span class="identifier">value_</span> <span class="special">=</span> <span class="identifier">m</span><span class="special">.</span><span class="identifier">value_</span><span class="special">;</span> <span class="identifier">m</span><span class="special">.</span><span class="identifier">value_</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="special">}</span> |
| |
| <span class="identifier">copy_movable</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">copy_movable</span> <span class="special">&</span><span class="identifier">m</span><span class="special">)</span> |
| <span class="special">{</span> <span class="identifier">value_</span> <span class="special">=</span> <span class="identifier">m</span><span class="special">.</span><span class="identifier">value_</span><span class="special">;</span> <span class="special">}</span> |
| |
| <span class="identifier">copy_movable</span> <span class="special">&</span> <span class="keyword">operator</span><span class="special">=(</span><span class="identifier">BOOST_RV_REF</span><span class="special">(</span><span class="identifier">copy_movable</span><span class="special">)</span> <span class="identifier">m</span><span class="special">)</span> |
| <span class="special">{</span> <span class="identifier">value_</span> <span class="special">=</span> <span class="identifier">m</span><span class="special">.</span><span class="identifier">value_</span><span class="special">;</span> <span class="identifier">m</span><span class="special">.</span><span class="identifier">value_</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span> <span class="special">}</span> |
| |
| <span class="identifier">copy_movable</span> <span class="special">&</span> <span class="keyword">operator</span><span class="special">=(</span><span class="identifier">BOOST_COPY_ASSIGN_REF</span><span class="special">(</span><span class="identifier">copy_movable</span><span class="special">)</span> <span class="identifier">m</span><span class="special">)</span> |
| <span class="special">{</span> <span class="identifier">value_</span> <span class="special">=</span> <span class="identifier">m</span><span class="special">.</span><span class="identifier">value_</span><span class="special">;</span> <span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span> <span class="special">}</span> |
| |
| <span class="keyword">bool</span> <span class="identifier">moved</span><span class="special">()</span> <span class="keyword">const</span> <span class="comment">//Observer</span> |
| <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">value_</span> <span class="special">==</span> <span class="number">0</span><span class="special">;</span> <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">//A copyable-only class</span> |
| <span class="keyword">class</span> <span class="identifier">copyable</span> |
| <span class="special">{};</span> |
| |
| <span class="comment">//A copyable-only class</span> |
| <span class="keyword">class</span> <span class="identifier">non_copy_movable</span> |
| <span class="special">{</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="identifier">non_copy_movable</span><span class="special">(){}</span> |
| <span class="keyword">private</span><span class="special">:</span> |
| <span class="identifier">non_copy_movable</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">non_copy_movable</span><span class="special">&);</span> |
| <span class="identifier">non_copy_movable</span><span class="special">&</span> <span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> <span class="identifier">non_copy_movable</span><span class="special">&);</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| and build a generic factory function that returns a newly constructed value |
| or a reference to an already constructed object. |
| </p> |
| <p> |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="string">"movable.hpp"</span> |
| <span class="preprocessor">#include</span> <span class="string">"copymovable.hpp"</span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">move</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">Type</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">factory_functor</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">Type</span> <span class="identifier">return_type</span><span class="special">;</span> |
| |
| <span class="identifier">Type</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="keyword">const</span> |
| <span class="special">{</span> <span class="identifier">Type</span> <span class="identifier">t</span><span class="special">;</span> <span class="keyword">return</span> <span class="identifier">BOOST_MOVE_RET</span><span class="special">(</span><span class="identifier">Type</span><span class="special">,</span> <span class="identifier">t</span><span class="special">);</span> <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">return_reference</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">non_copy_movable</span> <span class="special">&</span><span class="identifier">return_type</span><span class="special">;</span> |
| |
| <span class="identifier">non_copy_movable</span> <span class="special">&</span><span class="keyword">operator</span><span class="special">()()</span> <span class="keyword">const</span> |
| <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">ncm</span><span class="special">;</span> <span class="special">}</span> |
| |
| <span class="keyword">static</span> <span class="identifier">non_copy_movable</span> <span class="identifier">ncm</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="identifier">non_copy_movable</span> <span class="identifier">return_reference</span><span class="special">::</span><span class="identifier">ncm</span><span class="special">;</span> |
| |
| <span class="comment">//A wrapper that locks a mutex while the</span> |
| <span class="comment">//factory creates a new value.</span> |
| <span class="comment">//It must generically move the return value</span> |
| <span class="comment">//if possible both in C++03 and C++11</span> |
| <span class="keyword">template</span> <span class="special"><</span><span class="keyword">class</span> <span class="identifier">Factory</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">Factory</span><span class="special">::</span><span class="identifier">return_type</span> <span class="identifier">lock_wrapper</span><span class="special">(</span><span class="identifier">Factory</span> <span class="identifier">f</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">Factory</span><span class="special">::</span><span class="identifier">return_type</span> <span class="identifier">return_type</span><span class="special">;</span> |
| <span class="comment">//LOCK();</span> |
| <span class="identifier">return_type</span> <span class="identifier">r</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">();</span> |
| <span class="comment">//UNLOCK();</span> |
| |
| <span class="comment">//In C++03: boost::move() if R is not a reference and</span> |
| <span class="comment">//has move emulation enabled. In C++11: just return r.</span> |
| <span class="keyword">return</span> <span class="identifier">BOOST_MOVE_RET</span><span class="special">(</span><span class="identifier">return_type</span><span class="special">,</span> <span class="identifier">r</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">movable</span> <span class="identifier">m</span> <span class="special">=</span> <span class="identifier">lock_wrapper</span><span class="special">(</span><span class="identifier">factory_functor</span><span class="special"><</span><span class="identifier">movable</span><span class="special">></span> <span class="special">());</span> |
| <span class="identifier">copy_movable</span> <span class="identifier">cm</span> <span class="special">=</span> <span class="identifier">lock_wrapper</span><span class="special">(</span><span class="identifier">factory_functor</span><span class="special"><</span><span class="identifier">copy_movable</span><span class="special">>());</span> |
| <span class="identifier">copyable</span> <span class="identifier">c</span> <span class="special">=</span> <span class="identifier">lock_wrapper</span><span class="special">(</span><span class="identifier">factory_functor</span><span class="special"><</span><span class="identifier">copyable</span><span class="special">></span> <span class="special">());</span> |
| <span class="identifier">non_copy_movable</span> <span class="special">&</span><span class="identifier">mr</span> <span class="special">=</span> <span class="identifier">lock_wrapper</span><span class="special">(</span><span class="identifier">return_reference</span> <span class="special">());</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| <span class="bold"><strong>Caution</strong></span>: When using this macro in a non-conforming |
| or C++03 compilers, a move will be performed even if the C++11 standard does |
| not allow it (e.g. returning a static variable). The user is responsible for |
| using this macro only used to return local objects that met C++11 criteria. |
| E.g.: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">foo</span> |
| <span class="special">{</span> |
| <span class="identifier">copy_movable</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="comment">//ERROR! The Standard does not allow implicit move returns when the object to be returned </span> |
| <span class="comment">//does not met the criteria for elision of a copy operation (such as returning a static member data)</span> |
| <span class="comment">//In C++03 compilers this will MOVE resources from cm</span> |
| <span class="comment">//In C++11 compilers this will COPY resources from cm</span> |
| <span class="comment">//so DON'T use use BOOST_MOVE_RET without care.</span> |
| <span class="keyword">return</span> <span class="identifier">BOOST_MOVE_RET</span><span class="special">(</span><span class="identifier">copy_movable</span><span class="special">,</span> <span class="identifier">cm</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">static</span> <span class="identifier">copy_movable</span> <span class="identifier">cm</span><span class="special">;</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| <span class="bold"><strong>Note</strong></span>: When returning a temporary object <code class="computeroutput"><span class="identifier">BOOST_MOVE_REF</span></code> is not needed as copy ellision |
| rules will work on both C++03 and C++11 compilers. |
| </p> |
| <pre class="programlisting"><span class="comment">//Note: no BOOST_MOVE_RET</span> |
| <span class="identifier">movable</span> <span class="identifier">get_movable</span><span class="special">()</span> |
| <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">movable</span><span class="special">();</span> <span class="special">}</span> |
| |
| <span class="identifier">copy_movable</span> <span class="identifier">get_copy_movable</span><span class="special">()</span> |
| <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">copy_movable</span><span class="special">();</span> <span class="special">}</span> |
| |
| <span class="identifier">copyable</span> <span class="identifier">get_copyable</span><span class="special">()</span> |
| <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">copyable</span><span class="special">();</span> <span class="special">}</span> |
| </pre> |
| </div> |
| <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> |
| <td align="left"></td> |
| <td align="right"><div class="copyright-footer">Copyright © 2008-2014 Ion Gaztanaga<p> |
| Distributed under the Boost Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>) |
| </p> |
| </div></td> |
| </tr></table> |
| <hr> |
| <div class="spirit-nav"> |
| <a accesskey="p" href="construct_forwarding.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../move.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="move_iterator.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> |
| </div> |
| </body> |
| </html> |