Boost C++ Libraries: Ticket #5146: Assertion fails in visitation_impl.hpp with nested variants https://svn.boost.org/trac10/ticket/5146 <p> Let test_variant be following typedef: </p> <pre class="wiki">typedef variant &lt; int, ptr_to_test_variant &gt; test_variant ; </pre><p> ptr_to_test_variant is a simple class which contains a test_variant object allocated on the heap (to break the circular dependency, see attachment). </p> <p> Here is the test case: </p> <pre class="wiki">int main() { test_variant tv1 = 88; test_variant ptr_to_tv1 = ptr_to_test_variant(tv1); test_variant ptr_to_ptr_to_tv1 = ptr_to_test_variant(ptr_to_tv1); const ptr_to_test_variant&amp; direct_ptr_to_ptr_to_tv1 = get&lt;ptr_to_test_variant&gt;(ptr_to_ptr_to_tv1); ptr_to_ptr_to_tv1 = direct_ptr_to_ptr_to_tv1.pointed_test_variant(); } </pre><p> Here is the output: </p> <pre class="wiki">/usr/include/boost/variant/detail/visitation_impl.hpp:207: typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&amp;, VPCV, mpl_::true_, NBF, W*, S*) [with W = mpl_::int_&lt;20&gt;, S = boost::detail::variant::visitation_impl_step&lt;boost::mpl::l_iter&lt;boost::mpl::l_end&gt;, boost::mpl::l_iter&lt;boost::mpl::l_end&gt; &gt;, Visitor = boost::variant&lt;int, ptr_to_test_variant&gt;::convert_copy_into, VPCV = void*, NBF = boost::variant&lt;int, ptr_to_test_variant&gt;::has_fallback_type_, typename Visitor::result_type = int, mpl_::true_ = mpl_::bool_&lt;true&gt;]: Assertion `false' failed. </pre><p> I'm experiencing the exact same issue with my own implementation of stack-based variant (using variadic templates) as well. I'd like to know how to fix this… </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/5146 Trac 1.4.3 Florian Goujeon <flo.goujeon@…> Mon, 31 Jan 2011 22:08:18 GMT attachment set https://svn.boost.org/trac10/ticket/5146 https://svn.boost.org/trac10/ticket/5146 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">variant_bug.cpp</span> </li> </ul> Ticket Florian Goujeon <flo.goujeon@…> Tue, 01 Feb 2011 19:33:54 GMT <link>https://svn.boost.org/trac10/ticket/5146#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5146#comment:1</guid> <description> <p> OK, I got it. </p> <p> Since ptr_to_ptr_to_tv1 kinda contains direct_ptr_to_ptr_to_tv1, variant has to destruct direct_ptr_to_ptr_to_tv1 AFTER direct_ptr_to_ptr_to_tv1.pointed_test_variant() was copied into ptr_to_ptr_to_tv1. </p> <p> Currently, I guess variant clears its content (i.e. calls the destructor of its contained object) then sets it with a copy of the new object. This is the most natural behavior, but it causes problems when the copy constructor of the new object needs data that are stored in the previously contained object. </p> <p> I don't know the code of Boost.Variant, so I won't be able to write a patch. But basically, the changes I made in my implementation can be summarized like this: </p> <p> BEFORE: </p> <pre class="wiki">template&lt;typename Clear, typename Set&gt; void clear_and_set(const Set&amp; value) { (*reinterpret_cast&lt;Clear*&gt;(buffer_)).~Clear(); //clear new(buffer_) Set(value); //set } </pre><p> AFTER: </p> <pre class="wiki">template&lt;typename Clear, typename Set&gt; void clear_and_set(const Set&amp; value) { char old_buffer[Size]; for(unsigned int i = 0; i &lt; Size; ++i) { old_buffer[i] = buffer_[i]; } new(buffer_) Set(value); //set (*reinterpret_cast&lt;Clear*&gt;(old_buffer)).~Clear(); //clear } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Steven Watanabe</dc:creator> <pubDate>Fri, 11 Feb 2011 03:39:47 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/5146#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5146#comment:2</guid> <description> <p> Please see <a href="http://www.boost.org/doc/html/variant/design.html#variant.design.never-empty.memcpy-solution">The "Ideal" Solution: False Hopes</a> for an explanation of why this solution is evil. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Tue, 10 Dec 2013 15:02:54 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/5146#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5146#comment:3</guid> <description> <p> This looks more like a <code>ptr_to_test_variant</code> issue, not variant's one. </p> <p> Take a look at this code: </p> <pre class="wiki"> const ptr_to_test_variant&amp; direct_ptr_to_ptr_to_tv1 = get&lt;ptr_to_test_variant&gt;(ptr_to_ptr_to_tv1); ptr_to_ptr_to_tv1 = direct_ptr_to_ptr_to_tv1.pointed_test_variant(); </pre><p> You've got the chain: <code> ptr_to_ptr_to_tv1 -&gt; direct_ptr_to_ptr_to_tv1 -&gt; unnamed </code> </p> <p> Then you try to do the following: <code> ptr_to_ptr_to_tv1 = unnamed; </code> </p> <p> Before assigning anything to <code>ptr_to_ptr_to_tv1</code> it will delete the data it owns: </p> <pre class="wiki">delete direct_ptr_to_ptr_to_tv1; delete unnamed; </pre><p> And only after that will attempt to do the assignment, but <code>delete unnamed</code> is already called. </p> <p> Much better solution would be to modify code of <code>ptr_to_test_variant</code>, (you do know that loops are possible, so make small trick to workaround such cases): </p> <pre class="wiki">ptr_to_test_variant&amp; ptr_to_test_variant::operator=(const ptr_to_test_variant&amp; rhs) { test_variant* tmp_ptr = pointed_test_variant_; pointed_test_variant_ = new test_variant(*rhs.pointed_test_variant_); // Even if there was a loop, data is copied and new pointed_test_variant_ // does not depends on old data at all. We are free to delete the old data. delete tmp_ptr; return *this; } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Tue, 10 Dec 2013 15:03:39 GMT</pubDate> <title>owner, status changed https://svn.boost.org/trac10/ticket/5146#comment:4 https://svn.boost.org/trac10/ticket/5146#comment:4 <ul> <li><strong>owner</strong> changed from <span class="trac-author">ebf</span> to <span class="trac-author">Antony Polukhin</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> Ticket Antony Polukhin Tue, 10 Dec 2013 15:05:03 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/5146#comment:5 https://svn.boost.org/trac10/ticket/5146#comment:5 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">invalid</span> </li> </ul> Ticket