Boost C++ Libraries: Ticket #7718: Basic rvalue and C++11 support (part 2) https://svn.boost.org/trac10/ticket/7718 <p> This patch adds template &lt;class T&gt; variant(T&amp;&amp;) constructor to Boost.Variant for compilers with rvalue references support (rvalue emulation via Boost.Move is not used for compatability reasons). </p> <p> For more info see ticket <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/7620" title="#7620: Patches: Basic rvalue and C++11 support (closed: fixed)">#7620</a> </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/7718 Trac 1.4.3 Antony Polukhin Thu, 22 Nov 2012 17:52:28 GMT <link>https://svn.boost.org/trac10/ticket/7718#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:1</guid> <description> <p> 'variant_reference_test' currently fails with this patch. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Mon, 26 Nov 2012 19:31:44 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/7718 https://svn.boost.org/trac10/ticket/7718 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">rvalues2.patch</span> </li> </ul> Ticket Antony Polukhin Mon, 26 Nov 2012 19:33:21 GMT <link>https://svn.boost.org/trac10/ticket/7718#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:2</guid> <description> <p> Now compiles and passes 'variant_reference_test', but sigfaults at 'test3' </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Mon, 26 Nov 2012 19:35:06 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/7718 https://svn.boost.org/trac10/ticket/7718 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">rvalue_test.cpp</span> </li> </ul> <p> Updated tests (now tests variant usage with move-only containers) </p> Ticket Antony Polukhin Wed, 28 Nov 2012 19:20:21 GMT <link>https://svn.boost.org/trac10/ticket/7718#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:3</guid> <description> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/81617" title="Basic rvalues and C++11 support part 2 (refs #7718 , all bugs from ...">[81617]</a>) Basic rvalues and C++11 support part 2 (refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/7718" title="#7718: Patches: Basic rvalue and C++11 support (part 2) (closed: fixed)">#7718</a> , all bugs from patch were fixed) </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Sat, 01 Dec 2012 15:32:11 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:4</guid> <description> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/81652" title="Refs #7718 : Workaroung GCC-4.7.2 internal compiler error More ...">[81652]</a>) Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/7718" title="#7718: Patches: Basic rvalue and C++11 support (part 2) (closed: fixed)">#7718</a> : Workaroung GCC-4.7.2 internal compiler error More functions marked with BOOST_NOEXCEPT Added move constructors and move assignment operators to recursive_wrapper </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Sat, 08 Dec 2012 15:44:20 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/7718#comment:5 https://svn.boost.org/trac10/ticket/7718#comment:5 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/81793" title="Merge variant from trunk: * Fix #7718 (move constructor from template ...">[81793]</a>) Merge variant from trunk: </p> <ul><li>Fix <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/7718" title="#7718: Patches: Basic rvalue and C++11 support (part 2) (closed: fixed)">#7718</a> (move constructor from template type added) </li><li>More tests and minor bugfixes </li><li>Deprecated macros replaced with new ones (thanks to Marshall Clow) </li></ul> Ticket Joel de Guzman Sun, 06 Jan 2013 01:39:33 GMT status changed; resolution deleted https://svn.boost.org/trac10/ticket/7718#comment:6 https://svn.boost.org/trac10/ticket/7718#comment:6 <ul> <li><strong>status</strong> <span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span> </li> <li><strong>resolution</strong> <span class="trac-field-deleted">fixed</span> </li> </ul> <p> Hi, </p> <p> I just looked at the current state of variant and noticed that the implementation of recursive_variant's move ctor seems to be not as optimal as I hoped. The current implementation as written is: </p> <blockquote> <p> recursive_wrapper&lt;T&gt;::recursive_wrapper(recursive_wrapper&amp;&amp; operand) </p> <blockquote> <p> : p_(new T( detail::variant::move(operand.get()) )) </p> </blockquote> <p> { } </p> </blockquote> <p> Unless I am mistaken, I think the heap allocation is not needed and the target should simply grab the pointer and mark the source pointer as 0 (with additional checks for 0 in the dtor): </p> <blockquote> <p> template &lt;typename T&gt; recursive_wrapper&lt;T&gt;::recursive_wrapper(recursive_wrapper&amp;&amp; operand) </p> <blockquote> <p> : p_(operand.release()) </p> </blockquote> <p> { } </p> </blockquote> <blockquote> <p> template &lt;typename T&gt; T* recursive_wrapper&lt;T&gt;::release() { </p> <blockquote> <p> T* ptr = p_; p_ = 0; return ptr; </p> </blockquote> <p> } </p> </blockquote> <p> </p> <blockquote> <p> template &lt;typename T&gt; recursive_wrapper&lt;T&gt;::~recursive_wrapper() { </p> <blockquote> <p> if (p_) </p> <blockquote> <p> boost::checked_delete(p_); </p> </blockquote> </blockquote> <p> } </p> </blockquote> <p> The tests are running just fine (tested with gcc, msvc) with this (more optimal) implementation. I also run the Spirit test suite (Spirit makes heavy use of variant). </p> <p> Thoughts? I can commit this patch if it is acceptable. </p> Ticket anonymous Sun, 06 Jan 2013 23:50:15 GMT <link>https://svn.boost.org/trac10/ticket/7718#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:7</guid> <description> <p> Update. Just checked, the check for 0 is not needed. 0 is valid for checked_delete just like plain delete. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Sun, 20 Jan 2013 12:05:12 GMT</pubDate> <title>status, milestone changed; resolution set https://svn.boost.org/trac10/ticket/7718#comment:8 https://svn.boost.org/trac10/ticket/7718#comment:8 <ul> <li><strong>status</strong> <span class="trac-field-old">reopened</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.53.0</span> </li> </ul> <p> This issue was discussed in <a class="ext-link" href="http://lists.boost.org/Archives/boost/2013/01/200014.php"><span class="icon">​</span>mainling lists</a>. If in short we have to choose between thre solutions:<br /> 1) leave as is (slow move construction)<br /> 2) allow empty state (fast, but breaks users code and variant guarantees)<br /> 3) after move, do lazy default construction of value on request (fast, but adds default construction requirement for type and functions get() and get_ptr() may throw)<br /> </p> <p> There were more votes for solution 1. </p> Ticket Joel de Guzman Sun, 20 Jan 2013 15:26:56 GMT status changed; resolution deleted https://svn.boost.org/trac10/ticket/7718#comment:9 https://svn.boost.org/trac10/ticket/7718#comment:9 <ul> <li><strong>status</strong> <span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span> </li> <li><strong>resolution</strong> <span class="trac-field-deleted">fixed</span> </li> </ul> <p> There is no such vote! 2 is the current consensus, FYI. I will reopen this. This is not a closed issue, not especially the way you concluded it to be. </p> Ticket Joel de Guzman Sun, 20 Jan 2013 15:29:49 GMT <link>https://svn.boost.org/trac10/ticket/7718#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:10</guid> <description> <p> BTW, you are wrong about 2. The way Peter Dimov outlines the solution does not break users code and variant guarantees. Have you read Peter Dimov's solution? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Sun, 20 Jan 2013 15:32:00 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:11</guid> <description> <p> Let me quote in case you missed it: </p> <p> On 1/11/13 11:02 PM, Paul Smith wrote: </p> <blockquote class="citation"> <p> On Fri, Jan 11, 2013 at 4:18 PM, Peter Dimov &lt;lists@…&gt; wrote: </p> <blockquote class="citation"> <p> If the variant could be empty, or equivalently, if the variant always contained a type that can be reliably default-constructed (without an exception) such as int, the problems with assignment (both copy- and move-) and with move construction do not occur, because the target can be left holding the int. </p> <p> So, one option is to enable move only in this case. </p> </blockquote> <p> That's the first constructive solution so far. Something like: </p> <p> template &lt;typename T&gt; struct is_legitimate_move_target <em> specialize me </em></p> <blockquote> <p> : has_trivial_constructor&lt;T&gt; {}; </p> </blockquote> </blockquote> <p> Paul, I agree! </p> <p> Peter, I like the direction this is heading to. I really appreciate your interest in this. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Sun, 20 Jan 2013 16:04:17 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:12</guid> <description> <p> Sometimes I really miss a smiley that hits its head to the wall... </p> <p> Variant is not a recursive_wrapper, recursive_wrapper is not a variant. recursive_wrapper may be used without a variant. recursive_wrapper currently can not hold an empty state. All the solutions above (1, 2 and 3) are for recursive_wrapper only. </p> <p> Please, refer to the sources and documentation of variant. There you can find that solution of Peter Dimov already implemented... </p> <p> If you have some other ideas for optimizing variant, please tell me about them short and clear. Otherwise, please close the ticket. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Mon, 21 Jan 2013 00:31:03 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:13</guid> <description> <p> :-) There you go (smiley). I'm sorry if I overreacted. This issue is very important for me as I've invested heavily on variant and I expect an optimal solution to this problem. </p> <p> I know the code of variant and recursive_variant. This patch is about variant. recursive_wrapper happens to be an integral part of variant. No, the current code does not implement Peter Dimov's suggestion about move yet. If you think it does, then please point me to the location where this is implemented. </p> <p> The idea is simplified with Peter's note: </p> <p> &lt;quote&gt; </p> <blockquote> <p> No, I'm suggesting that move (in the presence of recursive_wrappers) can be enabled only when there is at least one type that is nothrow-default-constructible, regardless of whether it's current. </p> </blockquote> <blockquote> <p> typedef variant&lt;int, recursive_wrapper&lt;foo&gt;&gt; V; </p> </blockquote> <blockquote> <p> V v1( std::move(v2) ); </p> </blockquote> <blockquote> <p> This move-constructs v1 from v2 and leaves int() into v2. </p> </blockquote> <p> &lt;/quote&gt; </p> <p> So, this is a special case handling for recursive_variant. Depending on the implementation, there might be a friend relationship with variant in recursive_wrapper, allowing it to grab its contents and place it in the destination. </p> <p> Note: I'll just check the the first type. Variant's design somehow makes the first type important. It's the one that's default constructed and it's (almost always) a nothrow-default-constructible type. </p> <p> Tell me if you need help in implementing this. I know my way around variant. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Mon, 21 Jan 2013 06:29:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:14</guid> <description> <p> Now I've got the idea :-) . Yes, it is not currently implemented and will give a good speed boost.<br /> But in example above, won't the user be confused by v2 holding an int (instead of recursive_wrapper)? This proposal looks not much better than the first proposal, but requires more code to implement and adds 'friend' relationship (which is not nice). <br /> <br /> Maybe a more correct solution would be to create an additional class nullable_recursive_wrapper/lazy_recursive_wrapper, and possibly mark recursive_wrapper as a deprecated one? Or just use an unique_ptr/shared_ptr instead of it? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Mon, 21 Jan 2013 06:46:11 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:15 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:15</guid> <description> <p> No. As I said in the mailing list, this should happen only in the 0.0000001% of the cases. In 99.9999999% of the cases, when you move something, the next thing that will happen is that it will be destructed. Please read the extensive exchange on this matter in the list. Only in very rare occasions (dare I say reckless cases) will someone want to do something on a moved-from object after a move. In that case, documentation should be sufficient to make this clear. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Mon, 21 Jan 2013 06:58:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:16 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:16</guid> <description> <p> BTW, that "No" is in reply to "won't the user be confused by v2 holding an int (instead of recursive_wrapper)?". </p> <p> Perhaps there's a way to implement it without friend access, but I'm not sure. Anyway, the extra code is mostly TMP code for checking the the "blank" type. </p> <p> nullable_recursive_wrapper is a good idea, but there's this extra check for null on all access that makes it less optimal. And that null check will be there to make the 0.0000001% of the cases happy. I don't know what you mean by lazy_recursive_wrapper. Same thing? As for unique/shared_ptr, AFAICT, they won't work as plug-in replacements. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Mon, 21 Jan 2013 08:10:27 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:17 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:17</guid> <description> <p> First of all, I also dislike that 'new' call in move constructor, but I just do not see a better solution. Let me explain: </p> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7718#comment:16" title="Comment 16">djowel</a>: </p> <blockquote class="citation"> <p> BTW, that "No" is in reply to "won't the user be confused by v2 holding an int (instead of recursive_wrapper)?". </p> <p> Perhaps there's a way to implement it without friend access, but I'm not sure. Anyway, the extra code is mostly TMP code for checking the the "blank" type. </p> <p> nullable_recursive_wrapper is a good idea, but there's this extra check for null on all access that makes it less optimal. And that null check will be there to make the 0.0000001% of the cases happy. </p> </blockquote> <p> I'm trying to point, that solution that makes variant change its internal type is as good/bad for user, as a solution with nulling the pointer of recursive_wrapper. But nulling the pointer is much more easy to implement. </p> <p> Here is some comparison of solutions (as I see it): </p> <p> Nulling pointer after move constructor: <br /> 1) fast and efficient <br /> 2) triggers an assert when user tries to reuse moved object <br /> 3) must have a BOOST_ASSERT in get_pointer() finction <br /> 4) easy to implement <br /> 5) optimization will be used even if varinat has no type with trivial default constructor <br /> <br /> Make varinat change its internal type: <br /> 1) fast and efficient <br /> 2) obscures user, when he tries to reuse moved object <br /> 3) requires a few more assignments in variant for which_ and maybe for trivial type construction <br /> 4) hard to implement <br /> 5) optimization will be used only if varinat has no type with trivial default constructor <br /> <br /> </p> <blockquote class="citation"> <p> I don't know what you mean by lazy_recursive_wrapper. Same thing? </p> </blockquote> <p> It is an implementation, that after move does a lazy default construction of value on request. <br /> </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Mon, 21 Jan 2013 12:17:25 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:18 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:18</guid> <description> <p> To be honest, I still prefer nulling the pointer. However, people seem to agree that that will ultimately place a precondition on recursive_variant (which is not good on extremely rare cases). Me? I don't care much about that. IMO, it's just a matter of documentation that people should simply not use a moved-from object. </p> <p> The solution Peter suggested is a compromise. You do not need any asserts (which is present only on debug builds) and the variant's never-empty guarantee is not violated. If you are not happy with it, then you can probably ask for a vote in the Boost list. I'd personally vote for nulling the pointer. I'm sure many will too. </p> <p> Bottom line: Either way is fine by me. I don't care which way we choose as long as we don't choose the "leave it as is" route. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Mon, 21 Jan 2013 12:49:55 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:19 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:19</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7718#comment:18" title="Comment 18">djowel</a>: </p> <blockquote class="citation"> <p> To be honest, I still prefer nulling the pointer. </p> </blockquote> <p> Nulling a pointer looks like a less ugliest solution. I`ll start a vote in the Boost list (and hope this time, nulling a pointer will win). </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Thu, 02 May 2013 08:39:37 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:20 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:20</guid> <description> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/84104" title="Update docs of Boost.Variant. Add advice about recursive_wrapper ...">[84104]</a>) Update docs of Boost.Variant. Add advice about recursive_wrapper performance (refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/7718" title="#7718: Patches: Basic rvalue and C++11 support (part 2) (closed: fixed)">#7718</a>) </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Thu, 02 May 2013 09:12:23 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7718#comment:21 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7718#comment:21</guid> <description> <p> As a result of discussion at mailing list - adding an empty state to recursive_wrapper is not a good idea (unfortunately). Updated documentation contains note about that and an advice for achieving better performance. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Thu, 02 May 2013 09:58:58 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/7718#comment:22 https://svn.boost.org/trac10/ticket/7718#comment:22 <ul> <li><strong>status</strong> <span class="trac-field-old">reopened</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/84105" title="Merge from trunk: * Update docs of Boost.Variant. Add advice about ...">[84105]</a>) Merge from trunk: </p> <ul><li>Update docs of Boost.Variant. Add advice about recursive_wrapper performance (fixes <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/7718" title="#7718: Patches: Basic rvalue and C++11 support (part 2) (closed: fixed)">#7718</a>) </li></ul> Ticket