I have some code that tries to erase certain elements from an unordered_set. It is done in a loop. The crash happens after it removes the first element found. I currently don't have any other setup except an M1 Mac. The crash happens there but doesn't on online sites (such as Coliru). I am wondering if my code has any undefined behavior. Comments are welcome. Thanks a lot!
#include <unordered_set>
#include <iostream>
struct Point {
int x;
int y;
};
bool operator==(const Point& p1, const Point& p2)
{
return p1.x == p2.x && p1.y == p2.y;
}
struct PointHash
{
std::size_t operator() (const Point& p) const {
return std::hash<int>()(p.x) ^ std::hash<int>()(p.y);
}
};
int main()
{
std::unordered_set<Point, PointHash> S{Point{0,1}, Point{1,1}, Point{1,0}, Point{2,0}};
for (auto it = S.begin(); it != S.end(); it) {
if (it->x == 0)
it = S.erase(it);
}
for (auto&& p: S)
std::cout << p.x << ',' << p.y << std::endl;
}
Please not that I also tried for-range on the erase loop but got the same crash.
CodePudding user response:
Rewrite the for loop like
for (auto it = S.begin(); it != S.end(); ) {
if (it->x == 0)
it = S.erase(it);
else
it;
}
If the compiler supports C 20 then you can just write
std::erase_if( S, []( const auto &p ) { return p.x == 0; } );
Here is a demonstration program
#include <unordered_set>
#include <iostream>
struct Point {
int x;
int y;
};
bool operator==(const Point& p1, const Point& p2)
{
return p1.x == p2.x && p1.y == p2.y;
}
struct PointHash
{
std::size_t operator() (const Point& p) const {
return std::hash<int>()(p.x) ^ std::hash<int>()(p.y);
}
};
int main()
{
std::unordered_set<Point, PointHash> S{Point{0,1}, Point{1,1}, Point{1,0}, Point{2,0}};
for ( const auto &p : S )
std::cout << p.x << ',' << p.y << std::endl;
std::cout << '\n';
std::erase_if( S, []( const auto &p ) { return p.x == 0; } );
for ( const auto &p : S)
std::cout << p.x << ',' << p.y << std::endl;
}
The program output is
2,0
1,1
1,0
0,1
2,0
1,1
1,0