Boost C++ Libraries: Ticket #10777: unordered_map treats operator== on stateful allocators as stateless https://svn.boost.org/trac10/ticket/10777 <p> Hi, </p> <p> here is my problem: I have a stateful allocator that has a bunch of stuff inside of it. It can be move-assigned. The problem is that boost::unordered_map does this when you have propagate_on_container_move_assign typedeffed to true_type: </p> <pre class="wiki">my_alloc a; my_alloc b; a = std::move(b); ASSERT(a == b); </pre><p> That assert can obviously never be true if my_alloc is stateful, but this sequence of events currently happens in boost::unordered_map. </p> <p> Here is an allocator that shows the problem: </p> <pre class="wiki">#pragma once #include &lt;memory&gt; #include &lt;vector&gt; template&lt;typename T&gt; struct plalloc { typedef T value_type; plalloc() = default; template&lt;typename U&gt; plalloc(const plalloc&lt;U&gt; &amp;) {} plalloc(const plalloc &amp;) {} plalloc &amp; operator=(const plalloc &amp;) { return *this; } plalloc(plalloc &amp;&amp;) = default; plalloc &amp; operator=(plalloc &amp;&amp;) = default; typedef std::true_type propagate_on_container_copy_assignment; typedef std::true_type propagate_on_container_move_assignment; typedef std::true_type propagate_on_container_swap; bool operator==(const plalloc &amp; other) const { return this == &amp;other; } bool operator!=(const plalloc &amp; other) const { return !(*this == other); } T * allocate(size_t num_to_allocate) { if (num_to_allocate != 1) { return static_cast&lt;T *&gt;(::operator new(sizeof(T) * num_to_allocate)); } else if (available.empty()) { // first allocate 8, then double whenever // we run out of memory size_t to_allocate = 8 &lt;&lt; memory.size(); available.reserve(to_allocate); std::unique_ptr&lt;value_holder[]&gt; allocated(new value_holder[to_allocate]); value_holder * first_new = allocated.get(); memory.emplace_back(std::move(allocated)); size_t to_return = to_allocate - 1; for (size_t i = 0; i &lt; to_return; ++i) { available.push_back(std::addressof(first_new[i].value)); } return std::addressof(first_new[to_return].value); } else { T * result = available.back(); available.pop_back(); return result; } } void deallocate(T * ptr, size_t num_to_free) { if (num_to_free == 1) { available.push_back(ptr); } else { ::operator delete(ptr); } } // boilerplate that shouldn't be needed, except // libstdc++ doesn't use allocator_traits yet template&lt;typename U&gt; struct rebind { typedef plalloc&lt;U&gt; other; }; typedef T * pointer; typedef const T * const_pointer; typedef T &amp; reference; typedef const T &amp; const_reference; template&lt;typename U, typename... Args&gt; void construct(U * object, Args &amp;&amp;... args) { new (object) U(std::forward&lt;Args&gt;(args)...); } template&lt;typename U, typename... Args&gt; void construct(const U * object, Args &amp;&amp;... args) = delete; template&lt;typename U&gt; void destroy(U * object) { object-&gt;~U(); } private: union value_holder { value_holder() {} ~value_holder() {} T value; }; std::vector&lt;std::unique_ptr&lt;value_holder[]&gt;&gt; memory; std::vector&lt;T *&gt; available; }; </pre><p> And here is a sequence of events with which you can get it: </p> <pre class="wiki">boost::unordered_map&lt;int, int, std::hash&lt;int&gt;, std::equal_to&lt;int&gt;, plalloc&lt;int&gt;&gt; a = { { 1, 2 } }; boost::unordered_map&lt;int, int, std::hash&lt;int&gt;, std::equal_to&lt;int&gt;, plalloc&lt;int&gt;&gt; b = { { 3, 4 } }; boost::unordered_map&lt;int, int, std::hash&lt;int&gt;, std::equal_to&lt;int&gt;, plalloc&lt;int&gt;&gt; c = { { 5, 6 } }; a = std::move(b); a = c; </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/10777 Trac 1.4.3 Daniel James Sun, 09 Nov 2014 23:49:31 GMT status, description changed https://svn.boost.org/trac10/ticket/10777#comment:1 https://svn.boost.org/trac10/ticket/10777#comment:1 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> <li><strong>description</strong> modified (<a href="/trac10/ticket/10777?action=diff&amp;version=1">diff</a>) </li> </ul> <p> I've removed the assertion in develop. </p> <p> <a class="ext-link" href="https://github.com/boostorg/unordered/commit/31211a607f1c294f973eed10e54e461a8ef920ba"><span class="icon">​</span>https://github.com/boostorg/unordered/commit/31211a607f1c294f973eed10e54e461a8ef920ba</a> </p> Ticket Daniel James Tue, 12 May 2015 17:57:01 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/10777#comment:2 https://svn.boost.org/trac10/ticket/10777#comment:2 <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">fixed</span> </li> </ul> Ticket