This question already has an answer here:
-
Erasing elements from a vector
4 answers
Here my code. I want remove from vector all elements with successfully called method 'release'.
bool foo::release()
{
return true;
}
// ...
vector<foo> vec;
// ...
remove_if(vec.begin(), vec.end(), [](foo & f) { return f.release() == true; });
// ...
But remove_if
not deleting all elements from vector vec
. How remove_if
works?
std::remove_if
re-arranges the elements of the vector such that the elements you want to keep are in the range [vec.begin(), return_iterator)
(note the partially open range). So you need to call std::vector::erase
to make sure the vector contains only the desired elements. This is called the erase-remove idiom:
auto it = remove_if(vec.begin(),
vec.end(),
[](foo & f) { return f.release() == true; });
vec.erase(it, vec.end());
Here, I have split it into two lines for clarity, but it is often seen as a one-liner.
Because the remove_if
algorithm operates on a range of elements denoted by two forward iterators, it has no knowledge of the underlying container or collection.
Thus, no elements are actually removed from the container. Rather, all elements which don't fit the remove criteria are brought together to the front of the range, in the same relative order.
The remaining elements are left in a valid, but unspecified, state. When this is done, remove returns an iterator pointing one element past the last unremoved element.
To actually eliminate elements from the container, remove should be combined with the container's erase
member function (hence the name "erase-remove idiom").
- How to use remove-erase idiom for removing empty vectors in a vector?
- Erasing elements from a vector
std::remove
and std::remove_if
do not actually remove anything but just give you an iterator by which you can then erase elements using the appropriate member function of whatever container you use. In std::vector
's case, erase
.
I invite you to read this old article from Scott Meyers: "My Most Important C++ Aha! Moments...Ever":
It was thus with considerable shock and a feeling of betrayal that I discovered that applying remove to a container never changes the number of elements in the container, not even if you ask it to remove everything. Fraud! Deceit! False advertising!
See http://en.wikipedia.org/wiki/Erase-remove_idiom
std::remove_if
doesn't actually obliterate erase the elements. What it does is move the elements that satisfies the criteria into the end of the range. It then returns an iterator to the first element of the removed (which are actually just moved) elements. It is on you then to erase that range from the container.
vector<foo> vec;
auto remove_start = remove_if(vec.begin(), vec.end(), [](foo & f) { return f.release() == true; });
vec.erase(remove_start, vec.end());
or
vec.erase(remove_if(vec.begin(), vec.end(),
[](foo & f) { return f.release() == true; }),
vec.end());