关于C ++中STL容器的问题

时间:2013-08-17 19:12:37

标签: c++ c++11 stl unordered-map multimap

  1. std :: multimap和std :: unordered_multimap有多少次随机播放?我问,因为我的代码传递引用以区分具有相同哈希的条目,并且我想知道何时对它们运行引用重定向功能。

  2. 如果我这样做会怎样:

    std::multimap atable; //Type specification stuff left out
    //Code that pus in two entries with the same key, call that key foo
    int bar = atable[foo];
    
  3. 如果结果是unordered_multimap,结果会有所不同吗?

  4. 返回传递引用以区分具有相同哈希的条目。有没有更安全的方法呢?

  5. 如果我删除其中一个条目(这是读取std :: vector文档的建议),那么条目是否会移动?

3 个答案:

答案 0 :(得分:5)

不,任何操作过程中都不会损坏任何元素。

正如在this famous Q&A中所解释的,对于关联容器,插入/擦除时没有迭代器失效(除了当然要擦除的元素)。对于无序关联容器,在重新散列期间存在迭代器失效,标准说明(强调我的)

23.2.5无序关联容器[unord.req]

  

9无序关联容器的元素被组织成   桶。具有相同哈希码的密钥出现在同一个存储桶中。该   添加元素时,桶的数量会自动增加   一个无序的关联容器,这样的平均数   每桶的元素保持在一个边界之下。 重复无效   迭代器,更改元素之间的顺序,以及更改哪些更改   存储桶元素,但不会使指针无效或   对元素的引用。对于unordered_multiset和unordered_multimap,   rehashing保留了等价元素的相对排序。

同样,这不需要重新填充实际存储的元素(Key中的Valueunordered_map<Key, Value>类型),因为无序映射具有组织为链表的存储桶,存储元素(键值对)的迭代器同时具有元素指针和存储桶指针。 reshshing shuffles buckets,它使迭代器无效(因为它们的bucket指针无效),但没有指针或对元素本身的引用。这在another Q&A

中有详细解释

答案 1 :(得分:2)

  

std :: multimap和std :: unordered_multimap有多少次随机播放条目?

从不。指向任何关联容器的元素(包括集合,映射及其无序或“多”版本)的迭代器永远不会失效(除非它们指向的特定元素被删除)。换句话说,实际的元素永远不会“混乱”。这些都需要作为链接结构(例如,链接树)实现,这意味着只需更改几个指针就可以重新构造它们,而无需物理移动任何元素。

编辑:显然(参见TemplateRex'评论),无序容器的情况并非如此。在这种情况下,迭代器可能会失效,但元素本身不会移动。这些要求意味着一个没有后向指针的间接容器,我认为这是一个合理的选择,但不是我所期望的。

  

如果我这样做会发生什么:...(获取多图的[])...

operator[]未定义std::multimap(或无序版本)。那么,会发生什么?编译器错误会发生。

  

如果结果是unordered_multimap,结果会有所不同吗?

不,它是相同的,operator[]不存在。

  

返回传递引用以区分具有相同哈希的条目。有更安全的方法吗?

是的,建议的做法是使用迭代器引用map / set /的元素,而不是引用。元素的迭代器保证保持有效,并且它们是可复制的并且对它们具有正确的常量保护,这使它们成为“引用条目”的完美对象。

编辑:根据相同的评论,如果处理散列容器(无序容器),我将不得不建议使用指向元素的指针,因为不保证(按标准)迭代器保持有效。

答案 2 :(得分:1)

C ++标准库中的所有关联容器都是基于节点的,即它们的元素保持不变。但是,未指定在复制它之后或在传递给容器的临时对象上是否在对象上计算散列。我猜,通常在复制/移动对象之前计算哈希值。

要区分具有相同哈希的元素,您需要具有相等的函数:如果对象的位置导致它不同,则意味着所有对象都不同,您将无法查找它们所有。您需要为无序容器中的元素提供相等的函数,以定义键的等价性。对于有序关联,等价类基于严格的弱排序,即,在这样的表达式上(使用<而不是二进制谓词的可读性;任何定义严格弱顺序的二元谓词也可以工作) :

bool equivalent = !(a < b) && !(b < a);