Home > database >  Crash when erasing element from unordered_set in loop
Crash when erasing element from unordered_set in loop

Time:08-12

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
  • Related