How to use .erase() in while loop?

Refresh

April 2019

Views

85 time

1

background: This is program to add 1 to a number stored digit by digit in a vector.

Numbers having 0 in front are allowed as input but not as output. eg: 0123 & 123 are both valid input but 0124 is a invalid output while 124 is an valid output

problem: I want to use erase() to delete 0's in front of the output vector till an non zero value is found using the while loop at the bottom of the code. However the compiler returns a garbage value. another online compiler gives a segmentation fault. Rest of the code works fine when compiled without the while loop.

#include <iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> A = { 9, 9, 9 };
    A.insert(A.begin(), 0); /*--last carry may nonzero so new digit -*/
    vector<int>::reverse_iterator it;
    int c = 1;
    for (it = A.rbegin(); it != A.rend(); it++) /*----finds and adds carry---*/
    {
        int d = *it;
        d = d + c;
        c = d / 10;
        if (c == 0)
            *it = d;
        else
        {
            d = d % 10;
            *it = d;
        }

    }
    vector<int>::iterator iss;
    iss = A.begin();

Problem loop starts

    while (*iss == 0) /*----------------problem----------------*/
    {
        iss = A.erase(iss);
    }

loop Ends

    for (int i = 0; i < A.size(); i++)
    {
        cout << A[i];
    }
}

3 answers

0

Not obvious where exactly you see garbage, but you miss a check if the iterator is valid, e.g. while(iss != A.end() && *iss==0).

0

Instead of erasing item from a vector, it is almost always preferable (from a complexity point of view) to move items to preserve to another vector, move the objects to keep to another vector. This has also better performance (erasing from the head of the vector will move all other objects in the best case):

void remove_zeroes(std::vector<int>& v) {
    std::vector<int> saved;
    auto begin = std::find_if(v.begin(),v.end(),[](int x){ return x != 0; });
    for(auto it = begin; it != v.end(); it++) {
        saved.push_back(std::move(*it));
    }
    v.swap(saved);
}

Although in this case it is equivalent to just use the range erase method of std::vector, which takes two iterators as parameters (as suggested in other answer) this technique might be useful if the elements to remove aren't in a contiguous range.

1

What you've written is almost right. There should be an additional check for the end iterator.

while(iss != A.end() && *iss == 0) {
    iss = A.erase(iss);
}

However, it is possible to implement it so that the algorithm has better performance:

while(iss != A.end() && *iss == 0) {
    ++iss;
}
A.erase(A.begin(), iss);