简体   繁体   中英

Will elements added into a std::unordered_set (or unordered_map) during iteration be visited during the iterations?

I have code that looks like the below:

std::unordered_set<int> ht{1,2,3};
ht.reserve(10000);  // ht will not exceed this size

for(int i = 0; i < n; i++)
{ 
  auto j = i;
  for(auto it = ht.begin(); it != ht.end(); ++it)
  {
    // do some stuff
    int v = j++;
    ht.emplace(v);
  }
}

For the inner loop, I want to loop from the beginning of ht to the end, but I don't want the loop to go over any of the newly added elements within the loop. In other words, is the above equivalent to the below?

std::unordered_set<int> ht{1,2,3};
ht.reserve(10000);  // ht will not exceed this size

for(int i = 0; i < n; i++)
{
  auto temp = ht;
  auto j = i;
  for(auto it = ht.begin(); it != ht.end(); ++it)
  {
    // do some stuff
    auto v = j++;
    temp.emplace(j);
  }

  ht = temp;
}

Based on a few runs that I did, it seems to be equivalent, but I don't know if this is undefined behavior, or if they are indeed equivalent. If the unordered_set was changed to a vector , this would not work, but it seems the forward iterators work.

Does the answer change if the ht.reserve(10000); // ht will not exceed this size ht.reserve(10000); // ht will not exceed this size was not present or if ht did in fact exceed the reserved capacity, and therefore all the forward iterators will be invalidated?

No, it's not safe:

On most cases, all iterators in the container remain valid after the insertion. The only exception being when the growth of the container forces a rehash. In this case, all iterators in the container are invalidated.

Sometimes it works, but I don't think this is enough for you!

No. See cppreference on std::unordered_set .

Cppreference.com has Iterator invalidation sections which describe when an iterator is invalidated. In the case of using std::unordered_set , inserting is not safe when a rehash occurs.

Rehashing occurs only if the new number of elements is greater than max_load_factor()*bucket_count()

And you can not know for certain whether inserting an element will cause that to happen.

In your example, you don't actually dereference the iterator, so why not loop over the size of the set?

size_t limit = ht.size();
for (size_t i = 0; i < limit; ++i) {
    ...
}

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