Search code examples
c++stlerase-remove-idiom

std::erase and std::remove combination to delete specific element doesn't work for specific example


#include <vector>
#include <algorithm>

using namespace std;

int main() {
    vector<int> a = {1,2,3,7,1,5,4};
    vector<int> b = {6,7,4,3,3,1,7};
    a.erase(remove(a.begin(),a.end(),a[0]),a.end());
    b.erase(remove(b.begin(),b.end(),b[0]),b.end());

    return 1;
}

For this specific example, my GNU gdb Ubuntu 7.7.1 states that at return 1 line: a = {2,3,7,1,5,4} which is not expected (only deletes one 1), and b = {7,4,3,3,1} which is not expected.

My expectation is b should be a=2,3,7,5,4 and b=7,4,3,3,1,7.

What's happening here?


Solution

  • The declaration of std::remove() looks like

    template <class ForwardIterator, class T>
      ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);
    

    Note that the last parameter is a reference. Thus after compilation it effectively pass the address of the specified element.

    By remove(a.begin(), a.end(), a[0]), something indicating the address to the 0th element of a is passed in. When remove() is running, once the 0th element is handled, the value pointed by the reference passed in changed, which leads to the unexpected result.

    To get expected result, make a copy before calling std::remove().

    int toberemoved = a[0];
    a.erase(remove(a.begin(),a.end(),toberemoved),a.end());