0

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

Sandeep
  • 1,245
  • 1
  • 13
  • 33
  • 2
    You've done one half of the [erase-remove idiom](https://en.wikipedia.org/wiki/Erase%E2%80%93remove_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 Oct 01 '21 at 13:27
  • [Here is an example](https://godbolt.org/z/6zWWa1z59) with the explained steps. – Fareanor Oct 01 '21 at 13:39

3 Answers3

1

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.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • anyone reading this is going to wonder *why* it works that way! The answer is basically so you can mix-and-match different containers with different functions (like remove_if). Different containers have different ways to remove things, so you have to do that instead of remove_if doing it. – user253751 Oct 01 '21 at 14:28
0

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.

doctorlove
  • 18,872
  • 2
  • 46
  • 62
  • Or use `std::vector::erase()` with the returned interator (it seems the OP wants to remove the even elements from the vector). – Fareanor Oct 01 '21 at 13:46
0

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;
}
Lukas
  • 1,320
  • 12
  • 20