迭代std :: map vs std :: unordered_map的值类型的区别

sjd*_*ing 3 c++ stl c++11

以下程序迭代unordered_map尝试找到最佳元素但不完全返回预期结果:

#include <iostream>
#include <unordered_map>
using namespace std;

struct Item
{
    int val;
};

int main() {
    unordered_map<int, Item> itemMap;
    itemMap[0] = {0};
    itemMap[1] = {1};
    itemMap[2] = {2};
    itemMap[3] = {3};
    const Item* bestItem = nullptr;
    int bestVal = -1;
    for (const pair<int, Item>& item : itemMap)
    {
        if (item.second.val > bestVal)
        {
            bestVal = item.second.val;
            bestItem = &item.second;
        }
    }
    cout << "best val: " << bestVal << " best item: " << bestItem->val;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

ideone

运行此程序打印出来:

best val: 3 best item: 0

这似乎是因为value_typea unordered_map是,std::pair<const Key, T>但我们正在迭代const pair<int, Item>.果然改变这个const pair<const int, Item>导致:

best val: 3 best item: 3

但是,如果我们将类型更改itemMapstd::map:

map<int, Item> itemMap

然后,如果我们迭代const pair<int, Item>const pair<const int, Item>得到相同的结果无关紧要:

best val: 3 best item: 3

尽管value_typestd::map仍然是std::pair<const Key, T>.但为什么?

Mik*_*our 5

问题可以归结为"为什么未定义的行为会为不同的容器提供不同的结果?",答案是"因为它未定义".

不那么轻浮:你可能会看到最后一次迭代的价值,这在订购的情况下是最大的map,但可能是任何东西unordered_map.

根据你的描述,我想你明白为什么它是未定义的:一个const引用可以绑定到一个临时的,所以如果类型不完全匹配,它会这样做,而不是绑定到map元素本身.引用,因此临时,在循环中作用域,因此在外部不可用.你对它的悬空指针将最终指向重用该内存的任何东西 - 在这种情况下,这很可能是在循环的后续迭代中的相同变量.

正如您在评论中所说,使用auto &&(或者,可能更好auto const &),以便类型推导确保类型匹配,并且引用直接绑定到地图元素.然后指针将指向一个map元素,并且在循环外仍然有效.