STL remove doesn't work as expected?
int main()
{
const int SIZE = 10;
int a[SIZE] = {10, 2, 35, 5, 10, 26, 67, 2, 5, 10};
std::ostream_iterator< int > output(cout, " ");
std::vector< int > v(a, a + SIZE);
std::vector< int >::iterator newLastElement;
cout << "contents of the vector: ";
std::copy(v.begin(), v.end(), output);
newLastElement = std::remove(v.begin(), v.end(), 10);
cout << "\ncontents of the vector after remove: ";
//std::copy(v.begin(), newLastElement, output);
//this gives the correct result : 2 35 5 26 67 2 5
std::copy(v.begin(), v.end(), output);
//this gives a 10 which was supposed to be removed : 2 35 5 26 67 2 5 2 5 10
cout << endl;
return 0;
}
There are three 10 in the array a.
why does the array v contains a 10 after we remove the all the 10s with remove function.
you can see the compiled output also here
Actually std::remove
doesn't remove the item from the container. Quoted from here
Remove removes from the range
[first, last)
all elements that are equal tovalue
. That is, remove returns an iteratornew_last
such that the range[first, new_last)
contains no elements equal tovalue
. The iterators in the range[new_last, last)
are all still dereferenceable, but the elements that they point to are unspecified. Remove is stable, meaning that the relative order of elements that are not equal to value is unchanged.`
That is, std::remove
works with a pair of iterators only and does not know anything about the container which actually contains the items. In fact, it's not possible for std::remove
to know the underlying container, because there is no way it can go from a pair of iterators to discover about the container to which the iterators belong. So std::remove
doesn't really remove the items, simply because it cannot. The only way to actually remove an item from a container is to invoke a member function on that container.
So if you want to remove the items, then use Erase-Remove Idiom:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
The erase-remove idiom is so common and useful is that std::list
has added another member function called list::remove
which produces the same effect as that of the erase-remove
idiom.
std::list<int> l;
//...
l.remove(10); //it "actually" removes all elements with value 10!
That means, you don't need to use erase-remove
idiom when you work with std::list
. You can directly call its member function list::remove
.
The reason is that STL algorithms do not modify the size of the sequence. remove
, instead of actually erasing items, moves them and returns an iterator to the "new" end. That iterator can then be passed to the erase
member function of your container to actually perform the removal:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
By the way, this is known as the "erase-remove idiom".
EDIT: I was incorrect. See comments, and Nawaz's answer.
Because std::remove
doesn't actually shrink the container, it just moves all the elements down to to fill up the spot used by the "removed" element. For example, if you have a sequence 1 2 3 4 5
and use std::remove
to remove the value 2
, your sequence will look like 1 3 4 5 5
. If you then remove the value 4
, you'll get 1 3 5 5 5
. At no point does the sequence ever get told to be shorter.