0
votes

In the following sample code remove_if is supposed to delete all even numbers but it is not working as I expect. I am obviously doing something wrong since the output continues to show some even numbers, towards the end.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool
myCond(int i) { return i % 2 == 0; }


int
main ()
{
  vector<int> myVector = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22};
  
  remove_if(myVector.begin(), myVector.end(), myCond);
  
  for(int i : myVector) cout << i << " ";
  cout << endl;
  return 0;
}

output 11 13 15 17 19 16 17 18 19 20 22

3
You've done one half of the erase-remove idiom. You still need to do the erase. It's a bit of an implementation detail that you have to go through this two-step process.Nathan Pierson
Here is an example with the explained steps.Fareanor

3 Answers

1
votes

std::remove_if only move the elements that need to be removed to the end of the container, you still need to use vector::erase to actually erase them.

If your compiler supports C++20, then I recommend using std::erase_if which is more intuitive and less error-prone:

vector<int> myVector = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22};
std::erase_if(myVector, myCond);

Demo.

0
votes

remove_if returns an iterator - which will be the end of the rearranged items.

You can change you for loop to stop when it gets to the new end.

0
votes

std::remove_if returns an iterator to the first element removed. In other words, everything before the iterator is evaluated to be false.

Have a look at the reference, especially the Return value paragraph.

For us, this means we have to iterate to returned iterator (the new end) if we want to print the odd values -- or we erase all elements from the returned iterator to end().

#include <iostream>
#include <vector>
#include <algorithm>

bool myCond(int i) { return i % 2 == 0; }

int main () {
  std::vector<int> myVector = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22};
  
  auto rm_it = std::remove_if(myVector.begin(), myVector.end(), myCond);
        
  // Possibility 1: Print odd values
  auto it = myVector.cbegin();
  for (; it != rm_it; ++it) std::cout << *it << " ";
  std::cout << std::endl;
  
  // Possibility 2: Erase values from the vector
  myVector.erase(rm_it, myVector.end());
  for(int i : myVector) std::cout << i << " ";
  std::cout << std::endl;
  
  return 0;
}