I know that erasing elements from an associative container inside a for loop invalidates it.
Is it the case when using a range based loop?
#include <iostream>
#include <unordered_map>
#include <set>
#include <algorithm>
#include <ranges>
struct A {
int value;
// other members...
};
int main() {
std::unordered_map<std::string, std::set<A>> myMap;
// Assuming you have populated the map and the set
// Object of type A
A a;
for (auto& [key, valueSet] : myMap) {
valueSet.erase(a);
if (valueSet.empty()) {
myMap.erase(key);
}
}
return 0;
}
And how can the compiler detects it.
I run -fsanitize=address,undefined but gcc doesn't show any warning.
Generally yes, a range-based for loop is just using iterators under the hood. It effectively expands to:
Any operation which invalidates iterators might also interfere with a range-based for loop as a result.
std::unordered_map::eraseinvalidates the iterator to the erased element. In your case,erase(key)is unsafe, because it invalidates the__beginiterator which is used under the hood.++__beginwould then advance an invalidated iterator, which is undefined behavior.-fsanitize=address,undefineddoes catch this type of mistake. (See live example at Compiler Explorer). It is aheap-use-after-free. Are you sure that-fsanitizeis even supported on your platform? Maybe it doesn't do anything because you're using MinGW and an old version of GCC.