std::unordered_map<K,T>
提供find
等返回std::unordered_map<K,T>::iterator
的方法。据我所知,除非重新发生,否则迭代器仍然有效。
但我怀疑是没有保证可以绕过::iterator
- &gt; T *
- &gt; ::iterator
,类似于Linux链表中的“hack”。我认为因为迭代器只需要通过->second
取消引用,但我不知道在容器内部有一个持久的存储类型需要它。
所以,我是对的吗?我是否需要保留迭代器,或者T *ptr = &myiterator->second
以后可以反向转换为->second
成员的地址为ptr
的迭代器指针?
这个问题自然也适用于其他容器的迭代器。
答案 0 :(得分:2)
第一个问题很简单:通常,没有直接的方法从指向元素或值的指针获取迭代器。也就是说,要从一个值中获取迭代器,通常需要搜索容器。由于std::vector<T>
必须是连续的,因此您可以使用简单的计算从指针获取迭代器(这要求v
非空):
std::vector<T> v(...);
T* ptr = ...;
std::vector<T>::iterator it(v.begin() + (ptr - &v[0]));
要追踪迭代器和值是否保持稳定,并不完全是微不足道的,因为相关的保证分布在多个子句中,例如:
23.2.1 [container.requirements.general]第11段:
除非另有说明(显式或通过根据其他函数定义函数),调用容器成员函数或将容器作为参数传递给库函数不应使迭代器无效或更改对象的值在那个容器内。
23.2.4 [associative.reqmts]第9段:
insert和emplace成员不应影响迭代器和对容器的引用的有效性,擦除成员应仅使迭代器和对擦除元素的引用无效。
23.2.5 [unord.req]第9段:
... Rehashing使迭代器无效,元素之间的顺序更改以及更改桶元素出现的更改,但不会使指针或对元素的引用无效。 ...
23.2.5 [unord.req]第14段:
insert和emplace成员不应影响对容器元素的引用的有效性,但可能使容器的所有迭代器无效。 ...
23.2.5 [unord.req]第15段:
如果(N + n)<<>,则插入和插入成员不应影响迭代器的有效性。 z * B,其中N是插入操作之前容器中元素的数量,n是插入的元素数,B是容器的桶数,z是容器的最大负载因子。
上述条款应该是关联容器的迭代器有效性的重要条款。无序关联容器中的迭代器有效性完全取决于容器是否重新散列。似乎可以控制重组以避免它出乎意料地发生。
但是,无序容器的整个概念是使用find()
定位对象非常有效。永远不需要将迭代器存储到元素中,因为您可以找回它们。当然,如果您有std::unordered_multimap<K, V>
或std::unordered_multiset<V>
,您可能需要知道您正在查看哪些等效元素。
答案 1 :(得分:1)
关联容器(set
,multi_set
,map
,multi_map
及其unordered_
弟兄们)不无效指针向容器添加元素时的引用或引用;它们可以使迭代器无效。此外,删除元素时,只有迭代器,指针和对这些元素的引用无效。这样做的一个结果是,如果你获取一个元素的地址,只要该元素保留在容器中,该地址就会保持有效。
没有可移植的方法直接从元素的地址转换为指向该元素的迭代器。如果您需要这样做,您必须搜索元素。