Boost C++ Libraries: Ticket #9497: mpq_rational asserts when used in variant https://svn.boost.org/trac10/ticket/9497 <p> The following code fails with an assertion: </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#include</span> <span class="cpf">&lt;boost/variant.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/multiprecision/gmp.hpp&gt;</span><span class="cp"></span> <span class="k">struct</span> <span class="n">Foo</span> <span class="p">{</span> <span class="n">Foo</span><span class="p">()</span> <span class="p">{}</span> <span class="n">Foo</span><span class="p">(</span><span class="k">const</span> <span class="n">Foo</span><span class="o">&amp;</span><span class="p">)</span> <span class="p">{}</span> <span class="p">};</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="n">multiprecision</span><span class="o">::</span><span class="n">mpq_rational</span> <span class="n">Num</span><span class="p">;</span> <span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="n">Foo</span><span class="p">,</span> <span class="n">Num</span><span class="o">&gt;</span> <span class="n">Variant</span><span class="p">;</span> <span class="n">Variant</span> <span class="n">x</span> <span class="o">=</span> <span class="n">Num</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="n">Variant</span> <span class="n">y</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="n">x</span> <span class="o">=</span> <span class="n">Foo</span><span class="p">();</span> <span class="p">}</span> </pre></div></div><p> Assert text: </p> <pre class="wiki">test: /usr/local/include/boost/multiprecision/gmp.hpp:1947: __mpq_struct (&amp; boost::multiprecision::backends::gmp_rational::data())[1]: Assertion `m_data[0]._mp_num._mp_d' failed. Aborted </pre><p> Some notes on the code: </p> <ul><li>The explicit copy constructor for Foo is necessary </li><li>Replacing mpq_rational with mpz_int or cpp_rational doesn't cause assertion </li><li>Using boost::move without the -std=c++11 flag doesn't assert. (but it does assert with -std=c++11) </li></ul><p> Tested on Linux with: </p> <ul><li>g++-4.8.1, g++-4.8.2, clang 3.5 (trunk 197340) </li><li>boost-1.55.0 and trunk revision: 86799 </li><li>libgmp 5.1.0 </li></ul><p> Compiled with the command: (clan)g++ -std=c++11 main.cpp /usr/local/lib/libgmp.a -O0 -g </p> <p> The source of the problem could very well be in how variant handles move semantics in C++11 mode. </p> <p> Note: you can also find this file here: <a class="ext-link" href="https://gist.github.com/r0mai/7978397"><span class="icon">​</span>https://gist.github.com/r0mai/7978397</a> </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/9497 Trac 1.4.3 John Maddock Sat, 21 Dec 2013 17:12:12 GMT <link>https://svn.boost.org/trac10/ticket/9497#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9497#comment:1</guid> <description> <p> I'm unable to reproduce here - but I do notice that gmp_rational, unlike the other classes, does not allow a move-copy from an already moved-from source object. I've committed a tentative fix (see <a class="ext-link" href="https://github.com/boostorg/multiprecision/commit/f552968b21b2fd37c7ce69cb283d12d2c2a765bc"><span class="icon">​</span>https://github.com/boostorg/multiprecision/commit/f552968b21b2fd37c7ce69cb283d12d2c2a765bc</a>), can you please try that out and report back? </p> <p> Many thanks, John. </p> </description> <category>Ticket</category> </item> <item> <author>András Kucsma <r0maikx02b@…></author> <pubDate>Sat, 21 Dec 2013 17:42:01 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9497#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9497#comment:2</guid> <description> <p> Everything looks good with the patch. It doesn't assert anymore and behaves as expected. </p> <p> Thank you! </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Sat, 21 Dec 2013 18:08:35 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/9497#comment:3 https://svn.boost.org/trac10/ticket/9497#comment:3 <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> That's a relief then! </p> <p> Closing down. </p> Ticket John Maddock Sun, 22 Dec 2013 10:02:06 GMT status, component changed; resolution deleted https://svn.boost.org/trac10/ticket/9497#comment:4 https://svn.boost.org/trac10/ticket/9497#comment:4 <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> <li><strong>component</strong> <span class="trac-field-old">multiprecision</span> → <span class="trac-field-new">variant</span> </li> </ul> <p> See also <a class="ext-link" href="https://github.com/boostorg/multiprecision/commit/787cd1101e4bc1446206f6e345d023ca18ded09a"><span class="icon">​</span>https://github.com/boostorg/multiprecision/commit/787cd1101e4bc1446206f6e345d023ca18ded09a</a> </p> <p> I'm reopening and reassigning this as I don't really see why Variant would be move-copying from an already moved-from object. It might not be an issue, but it feels like a bug... </p> Ticket John Maddock Sun, 22 Dec 2013 10:02:26 GMT owner, status changed https://svn.boost.org/trac10/ticket/9497#comment:5 https://svn.boost.org/trac10/ticket/9497#comment:5 <ul> <li><strong>owner</strong> changed from <span class="trac-author">John Maddock</span> to <span class="trac-author">Antony Polukhin</span> </li> <li><strong>status</strong> <span class="trac-field-old">reopened</span> → <span class="trac-field-new">new</span> </li> </ul> Ticket Antony Polukhin Wed, 25 Dec 2013 08:58:26 GMT status changed https://svn.boost.org/trac10/ticket/9497#comment:6 https://svn.boost.org/trac10/ticket/9497#comment:6 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> Ticket Antony Polukhin Wed, 25 Dec 2013 12:03:20 GMT owner, status, component changed; cc set https://svn.boost.org/trac10/ticket/9497#comment:7 https://svn.boost.org/trac10/ticket/9497#comment:7 <ul> <li><strong>cc</strong> <span class="trac-author">antoshkka@…</span> added </li> <li><strong>owner</strong> changed from <span class="trac-author">Antony Polukhin</span> to <span class="trac-author">John Maddock</span> </li> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">new</span> </li> <li><strong>component</strong> <span class="trac-field-old">variant</span> → <span class="trac-field-new">multiprecision</span> </li> </ul> <p> It's not a bug, boost::variant tries to satisfy the never-empty guarantee: </p> <ul><li><code>boost::multiprecision::mpq_rational</code> has no noexcept default constructor because default constructor of <code>gmp_rational</code> is not marked with noexcept </li><li><code>Foo</code> has no noexcept default constructor </li><li>because of previous two points variant can not use <code>boost::multiprecision::mpq_rational</code> or <code>Foo</code> as fallback types </li><li>copy constructor of <code>Foo</code> is not noexcept, there is no fallback type in variant, so it attempts <strong>to copy/move content of variant to backup storage</strong> before doing an assignment of <code>Foo</code>. </li><li>... </li></ul><p> Looks like <code>gmp_rational</code> calls only pure C methods. Can the default constructor of <code>gmp_rational</code> be marked with noexcept? </p> Ticket John Maddock Tue, 11 Mar 2014 17:11:16 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/9497#comment:8 https://svn.boost.org/trac10/ticket/9497#comment:8 <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> <blockquote class="citation"> <p> Looks like gmp_rational calls only pure C methods. Can the default constructor of gmp_rational be marked with noexcept? </p> </blockquote> <p> Not really, as those methods perform memory allocation, and the allocator used can be a user-supplied custom one (which throws). In any case, if you're happy copying an already-moved-from-object and there's really no alternative, then that's fine. Closing down. </p> Ticket Antony Polukhin Tue, 11 Mar 2014 19:31:03 GMT <link>https://svn.boost.org/trac10/ticket/9497#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9497#comment:9</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/9497#comment:8" title="Comment 8">johnmaddock</a>: </p> <blockquote class="citation"> <p> In any case, if you're happy copying an already-moved-from-object and there's really no alternative, then that's fine. Closing down. </p> </blockquote> <p> I'm not 100% happy with that, but the only solution I see is to totally disable move assignments for cases when there is no fallback type. This can break user's code where variant is used with move-only types and there's no fallback. I'm in doubt. </p> </description> <category>Ticket</category> </item> </channel> </rss>