简体   繁体   中英

C++: cast from value type pointer to containing iterator

std::unordered_map<K,T> offers methods like find which return a std::unordered_map<K,T>::iterator . As far as I know, an iterator remains valid unless rehashing occurrs.

But my suspicion is that there is no guaranteed way for roundtripping ::iterator -> T * -> ::iterator , similar to the "hack" that is done in the Linux linked list. I think that because the iterator is only required to be dereferenceable via ->second , but I don't see where it is required to have a durable storage type inside the container.

So, am I right? Am I required to keep the iterator or is T *ptr = &myiterator->second later back-castable to an iterator pointer whose ->second member's address is ptr ?

This question is naturally also applicable to other container's iterators.

The first question is simple: in general, there is no direct way to get an iterator from a pointer to an element or from a value. That is, to get an iterator from a value you generally need to search the container. Since std::vector<T> is required to be contiguous you can get an iterator from a pointer using a simple computation (which requires that v is non-empty):

std::vector<T> v(...);
T* ptr = ...;
std::vector<T>::iterator it(v.begin() + (ptr - &v[0]));

To track down whether iterators and values stay stable, isn't entirely trivial as the relevant guarantees are distributed over multiple clauses, eg:

  1. 23.2.1 [container.requirements.general] paragraph 11:

    Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container.

  2. 23.2.4 [associative.reqmts] paragraph 9:

    The insert and emplace members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

  3. 23.2.5 [unord.req] paragraph 9:

    ... Rehashing invalidates iterators, changes ordering between elements, and changes which buckets elements appear in, but does not invalidate pointers or references to elements. ...

  4. 23.2.5 [unord.req] paragraph 14:

    The insert and emplace members shall not affect the validity of references to container elements, but may invalidate all iterators to the container. ...

  5. 23.2.5 [unord.req] paragraph 15:

    The insert and emplace members shall not affect the validity of iterators if (N+n) < z * B, where N is the number of elements in the container prior to the insert operation, n is the number of elements inserted, B is the container's bucket count, and z is the container's maximum load factor.

The above clauses should to be the important clauses with respect to iterator validity of the associative containers. The iterator validity in the unordered associative containers entirely depends on whether the container is rehashed. It seems the rehashing can be controlled to avoid it happening by surprise.

However, the entire idea of the unordered containers is that it is very efficient to locate an object using find() . It should never be necessary to store an iterator to an element because you can find them back. Of course, if you have a std::unordered_multimap<K, V> or a std::unordered_multiset<V> you may need to know which of the equivalent elements you are looking at.

Associative containers ( set , multi_set , map , multi_map , and their unordered_ brethren) do not invalidate pointers or references when you add elements to the container; they can invalidate iterators. In addition, when you remove elements, only iterators, pointers, and references to those elements are invalidated. One consequence of this is that if you take the address of an element, that address remains valid as long as that element remains in the container.

There is no portable way to directly convert from the address of an element to an iterator that points to that element. If you need to do this you have to search for the element.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM