我对这种行为感到好奇。我发现分配unordered_map
会更改无序地图的内部顺序,而不会插入/删除任何内容:
unordered_map<int, string> m1;
unordered_map<int, string> m2;
unordered_map<int, string> m3;
m1[2] = "john";
m1[4] = "sarah";
m1[1] = "mark";
m2 = m1;
m3 = m2;
for(auto it = m1.begin(); it != m1.end(); ++it) {
cout << it->second << " ";
}
cout << endl;
for(auto it = m2.begin(); it != m2.end(); ++it) {
cout << it->second << " ";
}
cout << endl;
for(auto it = m3.begin(); it != m3.end(); ++it) {
cout << it->second << " ";
}
cout << endl;
输出:
mark sarah john
john sarah mark
mark sarah john
我知道unordered_map
上没有任何特定的顺序,因为内部是一个哈希表,因此元素插入可以在任何地方结束,重新哈希将混合所有。< / p>
但是,这里的订单在分配后才会发生变化。我希望订单是相同的,因为我认为它只会复制底层存储。
我认为的第一个解释是,unordered_map
可能正在利用副本将新地图重新散列为更优化的排列。但是,我试图在m2的新地图(m3)上重复分配,m3的顺序不会保留。
为什么分配地图会改变顺序?
我的编译器是Apple LLVM版本8.1.0(clang-802.0.42)
答案 0 :(得分:2)
因为很明显这是特定于实现的(毕竟它是无序的地图)我会做出有根据的推测。
如果mark
和john
具有相同的散列并且碰撞有问题的存储区数量,并且实现使用链接,我们可以解释这一点。如果链接实现在前面插入新项目(即使对于单链接列表也是常量时间),那么每次分配容器时,都会交换链式项目顺序。
答案 1 :(得分:2)
这是libc++的实施细节:
_LIBCPP_INLINE_VISIBILITY unordered_map& operator=(const unordered_map& __u) { #ifndef _LIBCPP_CXX03_LANG __table_ = __u.__table_; #else if (this != &__u) { __table_.clear(); __table_.hash_function() = __u.__table_.hash_function(); __table_.key_eq() = __u.__table_.key_eq(); __table_.max_load_factor() = __u.__table_.max_load_factor(); __table_.__copy_assign_alloc(__u.__table_); insert(__u.begin(), __u.end()); } #endif return *this; }
From libc++'s unordered_map header
如果我们假设您使用的是C ++ 11或更高版本,那么这基本上可以通过清除旧的哈希表,然后将__u
的元素插入到此向量中来实现。
这意味着当你这样做时:
m2 = m1;
它大致相当于以下代码:
m2.clear();
m2.max_load_factor(m1.max_load_factor());
m2.insert(m1.begin(), m1.end());
当您使用libstdc++时,这不会发生,因为operator=
的实现只是= default
(请参阅libstdc ++&#39; s unordered_map header )