Simon
Simon

Reputation: 297

Erasing the last element of a vector by looping through it

I want to loop through a vector and erase certain elements that correspond to a certain criteria, for example:

vector<int> myvector;
vector<int>::iterator it;

myvector.push_back(1);
myvector.push_back(2);
myvector.push_back(3);
myvector.push_back(4);

for(it = myvector.begin(); it != myvector.end(); ++it){

    if((*it) == 4){
        it = myvector.erase(it);
    }
}

Now this works fine unless the criterion erases the last item like in the code above. How do you avoid this behaviour ?

Thanks.

EDIT------------------------------------

Now the reason I was looping through it was that there are actually 4 vectors I need to delete the element from (but the criterion is only on one vector):

In this case, is this how to go ?

vector<int> myvector;
vector<int> myvector2;
vector<int> myvector3;
vector<int> myvector4;
vector<int>::iterator it;
vector<int>::iterator it2;
vector<int>::iterator it3;
vector<int>::iterator it4;

myvector.push_back(1);
myvector.push_back(2);
myvector.push_back(3);
myvector.push_back(4);

(assume myvector2/3/4 have values inside them)

it2 = myvector2.begin()
it3 = myvector3.begin()
it4 = myvector4.begin()

for(it = myvector.begin(); it != myvector.end();){

    if((*it) == 4){
        it = myvector.erase(it);
        it2 = myvector2.erase(it2);
        it3 = myvector3.erase(it3);
        it4 = myvector4.erase(it4);
    }
    else{
    ++it;
    ++it2;
    ++it3;
    ++it4;
    }
}

Is there a modification to the erase/remove idiom valid in this case ?

Upvotes: 1

Views: 1297

Answers (5)

Sk Riyaz
Sk Riyaz

Reputation: 1

for(it = myvector.begin(); it < myvector.end(); ++it){

    if((*it) == 4){
        it = myvector.erase(it);
    }
}

This will make sure your loop will break if the it >= myvector.end().

Upvotes: 0

Jerry Coffin
Jerry Coffin

Reputation: 490108

The usual is the remove/erase idiom, which would look something like this:

myvector.erase(std::remove(myvector.begin(), myvector.end(), 4), myvector.end());

Edit: Rereading your question, you mention "certain criteria". If the criteria aren't necessarily just removing a single value, you can use std::remove_if instead of std::remove, and specify your criteria in a functor.

Edit2: for the version dealing with four vectors, the usual method is to create a struct holding the four related values, and delete entire structs:

struct x4 { 
    int a, b, c, d;

    // define equality based on the key field:
    bool operator==(x4 const &other) { return a == other.a; }

    x4(int a_, int b_=0, int c_=0, ind d_=0) : a(a_), b(b_), c(c_), d(d_) {}
};

std::vector<x4> myvector;

myvector.erase(std::remove(myvector.begin(), myvector.end(), x4(4));

Again, if your criteria are more complex than you can easily express in a comparison operator, you can use std::remove_if instead of std::remove. This is also useful if/when you might need to apply different criteria at different times.

If you really need to keep your data in parallel vectors (e.g., you're feeding the data to something external that requires separate, contiguous arrays), then using a loop is probably as good as the alternatives.

Upvotes: 5

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361352

I think you should write the loop as :

for(it = myvector.begin(); it != myvector.end(); )
{
    if((*it) == 4)
        it = myvector.erase(it);
    else
        ++it; //increment here!
}

Because in your code, if you find 4, you update it in the if block itself, but after that you again increment/update it in the for also which is wrong. That is why I moved it to else block that ensures that it gets incremented if you don't find 4 (or whatever value you're searching).

Also remember that erase returns iterator pointing to the new location of the element that followed the last element erased by the function call.

Upvotes: 2

Prasoon Saurav
Prasoon Saurav

Reputation: 92854

erase is generally used with remove (Also have a look at erase-remove idiom) as shown below

myvector.erase(std::remove(myvector.begin(), myvector.end(), 4), myvector.end());

Upvotes: 0

Mark B
Mark B

Reputation: 96241

Don't do this with a for loop, there's already a well-debugged algorithm for you.

myvector.erase(std::remove(myvector.begin(), myvector.end(), 4), myvector.end());

Upvotes: 3

Related Questions