Reputation: 215
This is a simple script I was working on, but I failed to understand why it was behaving unexpectedly.
Basically, I had an array of integers with duplicates, and I wanted to store the number of times an element occurred in the array along with the element's value in an unordered_map,
Then, for each entry in the map {k, v}, I needed to determine if k + 1 existed in the array, and if so, do something with it. Below you can see the code.
vector<int> A = {1, 1, 3, 2, 5, 3};
for (int i = 0; i < A.size(); ++i) m[A[i]]++;
int ans = 0;
for (const auto& e: m) {
if (m[e.first + 1] > 0) ans = max(ans, e.second + m[e.first + 1]);
}
Everything seemed to work. However, when k + 1 did not exist in the unordered_map, the loop would just terminate, and I do not understand why.
According to c++ documentation, the operator [] inserts a new element if it does not exist . But that does not tell me anything about the loop just not working.
I suspect it has something to do with the fact that I am modifying the unordered_map inside the loop. If this is the case, could you guys elaborate more on that?
I really appreciate your help.
Upvotes: 2
Views: 239
Reputation: 596592
Using m[e.first + 1]
inside your loop will insert a new element into m
if it does not exist, which will cause problems for the loop itself because a range-based for
loop uses iterators internally, and altering a std::unordered_map
while you are iterating through it with iterators is undefined behavior, as an insertion may invalidate the iterators:
If an insertion occurs and results in a rehashing of the container, all iterators are invalidated. Otherwise iterators are not affected. References are not invalidated. Rehashing occurs only if the new number of elements is greater than
max_load_factor()*bucket_count()
.
To avoid that, use the map's find()
method instead to check for a key's existence without inserting it:
for (const auto& e: m) {
auto iter = m.find(e.first + 1);
if (iter != m.end()) ans = max(ans, e.second + iter->second);
}
Upvotes: 6