【问题标题】:Why is std::unordered_map iterator not invalidated when we insert an element (apart from when rehashing occurs)?为什么当我们插入一个元素时 std::unordered_map 迭代器没有失效(除了重新散列发生时)?
【发布时间】:2018-10-18 18:02:48
【问题描述】:

根据stackoverflowcppreference 中描述的迭代器失效规则,我知道迭代器不会对 unordered_map 失效,除非发生重新散列。

如果我使用 std::vector 类比,那么这是否意味着所有插入都发生在迭代器当前指向的位置之前?

我正在修改我正在迭代的 unordered_map,并希望确保不会因迭代器失效而中断。我至少要确保避免使用 reserve 关键字unordered_map reserve

重新散列

这是我正在编写的示例代码:

// Function to return vector containing the subvector of inputVector with sum desiredSum, this function returns empty vector if sum not found
std::vector<int> sumVectorFunc(const std::vector<int>& inputVector, const int desiredSum){
    std::unordered_map< int,std::vector<int> > sumToSubVector{};
    sumToSubVector.reserve(desiredSum+1);
    // initialization with the zero sum
    sumToSubVector[0] = std::vector<int>{};


    for(auto itVector : inputVector){ // iterate over the vector of elements
        std::unordered_set<int> numbersAddedThisCycle{};    
        for(auto itSubVectors : sumToSubVector){ // iterate over constructed subVectors
            auto sum = itVector + itSubVectors.first;
            //the new sum constructed by adding this new vector element is not yet found and make sure that you are not adding the same element again and again to get new numbers
            if(sumToSubVector.find(sum) == sumToSubVector.end() && numbersAddedThisCycle.find(sum) == numbersAddedThisCycle.end()){   
                sumToSubVector[sum] = itSubVectors.second;
                sumToSubVector[sum].push_back(itVector);
                numbersAddedThisCycle.insert(sum);
            }
        }
    }

    // for(auto it : sumToSubVector){
    //     std::cout<<"FOr sum "<<it.first<<", we need the elements : ";
    //     for(auto it2 : it.second){
    //         std::cout<<it2<<" ";
    //     }std::cout<<"\n";
    // }

    return sumToSubVector[desiredSum];
}

我相信即使插入发生在迭代器位置之前,这个特定的实现也不会中断(即循环不会遍历在该特定插入循环中插入的元素)

总结问题:插入发生在哪里?我的循环将如何处理此插入?即使迭代器没有失效,迭代范围的unordered_map也明显改变了,这将如何影响循环?插入的元素是否可以在范围内跳过?

【问题讨论】:

  • 我应该提到上面的代码在我的测试用例中运行良好。
  • 我可以在插入总和不大于desiredSum的元素之前再添加一个条件,也假设所有数字都是正数(否则可能会发生rehash)
  • 你的问题起初让我很困惑,所以我冒昧地改写它,以便更清楚你的意思。如果我改变了你的意图,请纠正我。
  • 迭代器失效并不是你真正关心的。钱的报价是“我相信......循环不会遍历在那个特定插入周期中插入的元素”。这根本不能保证 - 元素以不确定的顺序枚举(因此 unordered 映射),并且迭代可能会或可能不会遇到新插入的元素。这与迭代器失效的问题无关;你在追逐一条红鲱鱼。
  • Igor,我相信您的评论已经消除了我最初的疑问。出于进一步的好奇,是否为 unordered_map 的新元素发生了链表样式的动态内存分配?

标签: c++ c++14 unordered-map


【解决方案1】:

为什么我们插入元素时std::unordered_map迭代器没有失效(除了重新散列发生时)?

这里std::unordered_mapstd::vector 有一定的相似之处,所有迭代器只有在超过容量并且数据被移动到更大的分配存储中时才会失效。

如果我使用std::vector 类比,那么这是否意味着所有插入都发生在迭代器当前指向的位置之前?

这里std::unordered_map 的行为与std::vector 不同。实际上,std::vector 中添加了push_back 的新元素出现在所有现有元素之后。但是在std::unordered_map 中,刚刚添加的元素可能出现在已经存在的元素之间(因此 unordered 映射,如 cmets 中所指出的)。

我的循环将如何处理此插入?

所以你的循环会通过刚刚添加的一些元素,而哪些添加的元素将被访问取决于库实现、哈希函数等。很可能你不喜欢它。所以你可以不立即在循环中添加std::unordered_map 中的元素,而是先将它们放在一个临时向量中,然后仅在循环之后将它们插入到地图中。

【讨论】:

    猜你喜欢
    • 2012-11-23
    • 2022-11-16
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    相关资源
    最近更新 更多