I've just lost three days of my life tracking down a very strange bug where unordered_map::insert() destroys the variable you insert. This highly non-obvious behaviour occurs in very recent compilers only: I found that clang 3.2-3.4 and GCC 4.8 are the only compilers to demonstrate this "feature".

Here's some reduced code from my main code base which demonstrates the issue:

#include <memory> #include <unordered_map> #include <iostream> int main(void) { std::unordered_map<int, std::shared_ptr<int>> map; auto a(std::make_pair(5, std::make_shared<int>(5))); std::cout << "a.second is " << a.second.get() << std::endl; map.insert(a); // Note we are NOT doing insert(std::move(a)) std::cout << "a.second is now " << a.second.get() << std::endl; return 0; }

I, like probably most C++ programmers, would expect output to look something like this:

a.second is 0x8c14048 a.second is now 0x8c14048

But with clang 3.2-3.4 and GCC 4.8 I get this instead:

a.second is 0xe03088 a.second is now 0

Which might make no sense, until you examine closely the docs for unordered_map::insert() at http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/ where overload no 2 is:

template <class P> pair<iterator,bool> insert ( P&& val );

Which is a greedy universal reference move overload, consuming anything not matching any of the other overloads, and move constructing it into a value_type. So why did our code above choose this overload, and not the unordered_map::value_type overload as probably most would expect?

The answer stares you in the face: unordered_map::value_type is a pair<const int, std::shared_ptr> and the compiler would correctly think that a pair<int, std::shared_ptr> isn't convertible. Therefore the compiler chooses the move universal reference overload, and that destroys the original, despite the programmer not using std::move() which is the typical convention for indicating you are okay with a variable getting destroyed. Therefore the insert destroying behaviour is in fact correct as per the C++11 standard, and older compilers were incorrect.

You can probably see now why I took three days to diagnose this bug. It was not at all obvious in a large code base where the type being inserted into unordered_map was a typedef defined far away in source code terms, and it never occurred to anyone to check if the typedef was identical to value_type.

So my questions to Stack Overflow: