#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";
}
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
为什么 mp.insert(std::pair
让我们按照我的看法来分解它。
为什么 Foo 的 move ctor 在第一次插入时被调用,而 Foo 的 copy ctor 在第二次插入时被调用?
执行了隐式转换,但不是按照您期望的方式执行。使用
insert()
方法的不同重载,它本身执行转换。更准确地说:
template<class P> iterator insert(P && value);
,因为该对不是 const value_type &
类型,也不是 value_type &&
或 node_type &&
类型,这是这里其他可能的单参数重载。有关所有重载,请参阅 C++ 参考 unordered_map::insert()
。问题在于,只有当
std::pair<const Foo, int>
定义了 const 右值移动构造函数(即 Foo
)时,才可能进行 Foo(const Foo && other)
的移动。由于该特定构造函数不存在,编译器必须求助于该对的复制构造函数,这就是调用该构造函数的原因。
(并不是说你应该定义const右值移动构造函数。除非你在非常特定的情况下绝对需要它们,否则我会避免它们,因为它会增加额外的复杂性,从而使你的类的推理变得更加困难。)
unordered_map::emplace
。