Search code examples
c++vectorsegmentation-faultc++14

Why do I get a segmentation fault when looping through this vector?


When I run this code I get a segmentation fault. I'm using C++ 14 with Clion. It looks like it crashes on the 6th or 7th loop. It seems like it is coming from where I am erasing elements from the vector. If there is a better way to iterate through vectors please let me know, I'm still trying to learn to code in C++.

#include <vector>
#include <synchapi.h>

class someClass{
public:
    int x;
    int y;
    int health = 0;
    someClass(int a, int b){
        x = a;
        y = b;
    }
};

std::vector<someClass> classList;

int main() {

    for (int i = 0; i < 7; ++i) {
        someClass newclass(i, i*3);
        classList.push_back(newclass);
    }

    while(true) {
        int iter = 0;
        if(!classList.empty()) {
            for (auto &e: classList) {

                if (e.health == 0) {
                    classList.erase(classList.begin() + iter); 
                    if(iter != 0){
                        iter--;
                    }
                }
                iter++;
            }
        }
        Sleep(50);
    }
    return 0;
}

Solution

  • When you modify a collection while iterating over it, bad things tend to happen.

    If you need to modify the original collection, use the remove-erase idiom.

    std::erase(
      std::remove_if(
        classList.begin(), classList.end(),
        [](auto &x){ return x.health == 0; }
      ),
      classList.end()
    );
    

    If you don't need to modify the original collection, you might copy the elements you don't want to remove to a new collection.

    std::vector<someClass> classList2;
    
    std::copy_if(
      classList.begin(), classList.end(),
      std::back_inserter(classList2),
      [](auto &x){ return x.health != 0; }
    );
    

    As a style note, using "list" in the name of a variable that is a vector is a bit misleading. As variable names should denote meaning of the data rather than type, it would be best to avoid this type of naming altogether.