omegasbk omegasbk - 3 months ago 21
C++ Question

Using erase-remove_if idiom

Let's say I have

std::vector<std::pair<int,Direction>>
.

I am trying to use erase-remove_if idiom to remove pairs from the vector.

stopPoints.erase(std::remove_if(stopPoints.begin(),
stopPoints.end(),
[&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; }));


I want to delete all pairs that have .first value set to 4.

In my example I have pairs:

- 4, Up
- 4, Down
- 2, Up
- 6, Up


However, after I execute erase-remove_if, I am left with:

- 2, Up
- 6, Up
- 6, Up


What am I doing wrong here?

Answer

The correct code is:

stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool 
                                       { return stopPoint.first == 4; }), 
                 stopPoints.end());

You need to remove the range starting from the iterator returned from std::remove_if to the end of the vector, not only a single element.

"Why?"

  • std::remove_if swaps elements around inside the vector in order to put all elements that do not match the predicate towards the beginning of the container.

    • It then returns the iterator that points to the first predicate-matching element.

    • std::vector::erase needs to erase the range starting from the returned iterator to the end of the vector, in order to remove all elements that match the predicate.


More information: Erase-remove idiom (Wikipedia).

Comments