1

I wrote a small program to remove 0's from a vector. But when I check, there is still a zero in the vector. why?

The size says its 4 when it should be 3 and there is still a zero showing.

int main()
{

    vector<int> nums1 = {1, 2, 3, 0, 0, 0};

    for(int i=0; i< nums1.size(); i++)
    {
        if(nums1[i] == 0)
            nums1.erase(nums1.begin() + i);
    }
    cout << "size is now: " << nums1.size() << endl;

    for(int j=0; j<nums1.size(); j++)
        cout<< nums1[j] << endl;
    return 0;
}
François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • 6
    You shouldn't increment `i` when the iteration erased an element. Otherwise you skip the element that now occupies the position of the element you removed. You should step through your code with a debugger to see what happens. – François Andrieux Aug 20 '21 at 20:55
  • Also I'd recommend to read about [iterators](https://www.geeksforgeeks.org/introduction-iterators-c/). – Karen Baghdasaryan Aug 20 '21 at 21:00
  • 3
    Use an iterator for enumeration and take advantage of the return value of `erase`. Better still, use the [remove/erase idiom](https://stackoverflow.com/questions/347441/erasing-elements-from-a-vector) – WhozCraig Aug 20 '21 at 21:01
  • You may want to read [How do I remove an item from a stl vector with a certain value?](https://stackoverflow.com/questions/39912/how-do-i-remove-an-item-from-a-stl-vector-with-a-certain-value) for a better way to do this. – Retired Ninja Aug 20 '21 at 21:01
  • If you’re going to be removing items from the vector you might consider iterating backwards (eg for (int i = v.size()-1; i >= 0; i—) {…} ), that way you don’t have make your integer-index modification conditional. – Jeremy Friesner Aug 20 '21 at 21:12
  • 2
    "_to remove 0's from a vector_" - Since C++20: [`std::erase/erase_if(std::vector)`](https://en.cppreference.com/w/cpp/container/vector/erase2) – Ted Lyngmo Aug 20 '21 at 21:14

3 Answers3

5

As mentioned in the comment, when you erase, your vector is modified, so you must not increment your iterator in the same way.

A more idiomatic way is:

for(auto i=nums1.begin(); i != nums1.end(); )
{
    if(*i == 0)
        i = nums1.erase(i); // when erased, move to element after erased one
    else
        i++; // otherwise, increment
}
Jeffrey
  • 11,063
  • 1
  • 21
  • 42
5

When an element of the vector is erased then all elements that follow it are moved left occupying the position of the erased element.

That is if the element at the position i was erased then the element that follows it now will be at this position. So you shall not increase the position.

For example

for(  std::vector<int>::size_type i=0; i < nums1.size(); )
{
    if(nums1[i] == 0)
        nums1.erase(nums1.begin() + i);
    else
        ++i;
}

Pay attention to that before the C++ 20 Standard you could use the standard algorithm std::remove like

nums1.erase( std::remove( nums1.begin(), nums1.end(), 0 ), nums1.end() );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

It's also worth mentioning, if you're using C++20 the standard library has improved support for this, which is much more clean, succinct, and less error prone:

#include <vector>
#include <algorithm>

int main() {
    std::vector v{1, 2, 0, 0, 0, 5};
    std::erase(v, 0);
}

Leaving v holding: {1, 2, 5}

Chris Uzdavinis
  • 6,022
  • 9
  • 16