std::remove_if not working properly [duplicate]
Asked Answered
Z

4

5

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?

Zach answered 29/3, 2014 at 10:35 Comment(0)
C
18

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.

Chelton answered 29/3, 2014 at 10:40 Comment(0)
H
2

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!

Hoarfrost answered 29/3, 2014 at 10:41 Comment(0)
L
1

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").

Lixivium answered 29/3, 2014 at 10:39 Comment(0)
F
0

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());
Forland answered 29/3, 2014 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.