I have a std::list of objects. The list is sorted and must stay that way. I need to find those objects that satisfy a certain criterion (I have a predicate for this), pass them to a function, and then delete the objects from the list.
It's not too hard to write a loop that calls std::find_if()
, invokes the operation on its result (if any), calls list.erase()
, and passes the result of that as begin iterator to the next call to std::find_if()
. IME, however, people find such code harder to read than it is to write it.
So I would preferably employ some algorithm(s) from the std lib rather than writing my own loop.
One idea was to (ab)use std::list<>::remove_if()
: Invoke the operation on the elements that match _from the predicate, before it returns true
, so that the list will delete the elements. Would that be standard-conforming? (The items themselves won't be changed, only data they refer to.)
Or can you come up with a better solution? (Again, the main objective is to make this easy to read and understand.) Maybe it's because I just ran into it, but to me it seems this might not be an uncommon usage pattern for a sequence of objects.
Note: For the time being , we're firmly stuck in C++03 land. :-/
C++11/14/17 solutions would be interesting and thus welcome, but I do need something that works with C++03.
std :: removeTransforms the range [first,last) into a range with all the elements that compare equal to val removed, and returns an iterator to the new end of that range. The function cannot alter the properties of the object containing the range of elements (i.e., it cannot alter the size of an array or a container).
C++ Algorithm remove_if() function is used to eliminate all the elements that satisfy a predicate from a given range [first, last) without disturbing the order of the remaining elements. This function cannot alter the size of the container. It returns an iterator to the new end of the range.
Can I abuse a predicate to perform operations on the elements before
remove_if
removes them?
Yes. There's nothing in the standard specification that requires the predicate to be a pure function. So this C++11 solution would be perfectly fine:
my_list.remove_if([f, pred](Elem const& e){
if (pred(e)) {
f(e);
return true;
}
return false;
});
Nothing even requires the predicate to ever return true
. You can even use remove_if
as a poor man's, unnecessarily confusing for_each
:
my_list.remove_if([f](Elem const& e){
f(e);
return false;
});
That's pointless and inefficient, but it's definitely standards conforming.
You can write the equivalent in C++03 as a function object. Whether or not you find that easier to read than the for loop is a matter of opinion. But it's not wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With