Code
#include <iostream>
#include <unordered_map>
#include <utility>
using namespace std;
struct Foo {
Foo(const int value) : val(value) {
cout << "Foo(int), val: " << val << '\n';
}
Foo(Foo & foo) {
val = foo.val;
cout << "Foo(Foo &)" << '\n';
}
Foo(const Foo & foo) {
val = foo.val;
cout << "Foo(const Foo &)" << '\n';
}
Foo(Foo && foo) {
val = foo.val;
cout << "Foo(Foo &&)" << '\n';
}
~Foo() { cout << "~Foo(), val: " << val << '\n'; }
Foo& operator=(const Foo& rhs)
{
cout << "Foo& operator=(const Foo& rhs), rhs.val: " << rhs.val;
val = rhs.val;
return *this;
}
bool operator==(const Foo& rhs) const { return val == rhs.val; }
bool operator<(const Foo& rhs) const { return val < rhs.val; }
int val;
};
template<> struct std::hash<Foo> {
size_t operator()(const Foo& f) const { return hash<int>{}(f.val); }
};
int main()
{
std::unordered_map<Foo, int> mp;
mp.insert(std::pair<Foo, int>{1, 50});
std::cout << '\n';
mp.insert(std::pair<const Foo, int>{2, 60});
std::cout << '\n';
std::cout << "exiting main()\n";
}
Output
Foo(int), val: 1
Foo(Foo &&)
~Foo(), val: 1
Foo(int), val: 2
Foo(const Foo &)
~Foo(), val: 2
exiting main()
~Foo(), val: 1
~Foo(), val: 2
Question #1
Why does mp.insert(std::pair<Foo, int>{1, 50}) compile? Does an implicit conversion occur?
Let's break it down as I see it.
Foo(int)with val 1 is called when temporarystd::pairis created, val 1 is provided to Foo ctor. Foo(int), val: 1 is printed.std::pair<iterator, bool> insert(value_type && value)is called with temporary pair provided as argument. How? Thestd::unordered_map<Foo, int>::value_typeisstd::pair<const Foo, int>. Does an implicit conversion fromstd::unordered_map<Foo, int>tostd::unordered_map<const Foo, int>occur here? If so, should the copy ctor be invoked here?- key is searched in the map. The key is not found, so the node is allocated and initialized with
std::pair{std::move(value)};ctor.Foo(Foo &&)is printed. - Temporary pair object is destructed. ~Foo(), val: 1 is printed.
Question #2
Why Foo's move ctor is called on the first insert and Foo's copy ctor is called on the second insert?
std::pair<const Foo, int>{2, 60}has aconst Foo. const objects cannot be moved as moving modifies an object.move(val).