I fill a std::unordered_map
using the insert
or emplace
methods and the move semantics. When a key clash occurs the element is not inserted in the map but the moved element is erased anyway:
#include <unordered_map>
#include <iostream>
int main(){
std::unordered_map<int, std::string> m;
m.insert(std::make_pair<int, std::string>(0, "test"));
std::string s = "test";
// try insert
auto val = std::make_pair<int, std::string>(0, std::move(s));
if(m.insert(std::move(val)).second){
std::cout << "insert successful, ";
}else{
std::cout << "insert failed, ";
}
std::cout << "s: " << s << ", val.second: " << val.second << std::endl;
// try emplace
s = "test";
if(m.emplace(0, std::move(s)).second){
std::cout << "emplace successful, ";
}else{
std::cout << "emplace failed, ";
}
std::cout << "s: " << s << std::endl;
return 0;
}
Output:
insert failed, s: , val.second:
emplace failed, s:
Thus nothing is inserted but the object (the string in the example) is erased anyway, making it impossible to use it for any other purpose. Possible fixes would be to not use move semantics or to check for the key prior to the insertion/emplacement, both of which have a performance penalty.
To resume, I understand that move semantics implies that a moved object is left in a state which is useful just for destruction, but I don't fully understand why a failed move operation in std::unordered_map
should anyway lead to that state, and if there is any code pattern that allows to avoid this without too much performance penalty.