Seg fault with iterators in a recursive function

2019-07-25 14:09发布

问题:

I'm trying to sort integers in a vector using a recursive function. My program runs, compiles, and sorts the data, but after the fact it gives me a seg fault. I think its because of the for loop using the addresses in the vector that have been changed causing it to never leave the loop.

void Plays::SortRelevance(vector<Plays> list){

cout << "in the loop" << endl;

for(vector<Plays>::iterator i=list.begin(); i != list.end(); ++i){
    cout << i->relevance << endl;
}

for(vector<Plays>::iterator i=list.begin(); i != list.end(); ++i){
    if(i->relevance < (i+1)->relevance){
        cout << "IN THE THINGY WAT" << endl;
        Plays temp(*i);
        list.erase (i);
        list.push_back (temp);
        SortRelevance(list);
        cout << "left recursive" << endl;

    }

    cout << "stuck?" << endl;
}
cout << "left the loop" << endl;
for(vector<Plays>::iterator i=list.begin(); i != list.end(); ++i){
    cout << i->relevance << endl;
}

}

The end of my output is as follows, sorted but giving a seg fault at the end:

    IN THE THINGY WAT
in the loop
-62
-62
-62
-69
-71
-72
-80
-81
-87
-89
-94
-100
-104
-107
-107
-112
-137
-142
-145
-150
-151
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
stuck?
Segmentation fault

Thanks in advance to anyone who can shed some light on this for me.

EDIT: I haven't so much as fixed the problem as I have found a better and more elegant way to do it. I created a class, overloaded the operators and then used the sort() function to sort what I needed to do.

回答1:

You mustn't operate on invalid iterators, and erase(it) invalidates it. The typical erase loop looks like this:

for (auto it = v.cbegin(); it != v.cend() /* not hoisted */; /* no increment */)
{
    if (delete_condition)
    {
        it = v.erase(it);    // or "v.erase(it++);"
    }
    else
    {
        ++it;
    }
}

(There has been some clean-up in the standard library in C++11 to make all container-erase functions return the next iterator, but that didn't use to be the case, and the version with it++ may be work on more platforms.)



回答2:

void Plays::SortRelevance(vector<Plays> list){

This signature is taking a copy of the list every time. You probably want that to be a reference.

if(i->relevance < (i+1)->relevance){

When i is the last element (i.e. i+1==list.end()), this is going out of bounds.

list.erase (i);

This line invalidates all the iterators for list (which is a terrible name -- it's a vector, not a list). This now means that i is invalid, so the next ++i of the loop is just as invalid.