Predicates

Gotchas (Effective STL also mentions this gotcha):

1) Predicates should be always stateless.
2) The operator() member function should be always const


class Nth { // function object that returns true for the nth call
private:
    int nth; // call for which to return true
    int count; // call counter
public:
    Nth (int n) : nth(n), count(0) {  // having state indicates problem
    }
    bool operator() (int) {  // non-const member operation() function indicates problem
        return ++count == nth;
    }
};

list<int> coll = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
list<int>::iterator pos;
pos = remove_if(coll.begin(),coll.end(), // range
Nth(3)); // remove criterion
coll.erase(pos,coll.end());

// May have other output depending on the STL implementation.
Output: 1 2 4 5 7 8 9 10

Root cause:
The algorithm uses find_if() to find the first element that should be removed. However, the
algorithm then uses a copy of the passed predicate op to process the remaining elements, if any.
Here, Nth in its original state is used again and also removes the third element of the remaining
elements, which is in fact the sixth element.

template <typename ForwIter, typename Predicate>
ForwIter std::remove_if(ForwIter beg, ForwIter end, Predicate op)
{
    beg = find_if(beg, end, op);  // find_if takes a copy of 'op'
    if (beg == end) {
        return beg;
    }
    else {
        ForwIter next = beg;
        return remove_copy_if(++next, end, beg, op);  // here 'op' still have the original state.
    }
}

Solution: Use lambdas
int count=0; // call counter
pos = remove_if(coll.begin(),coll.end(),   [&count] (int) {
                                                                        return ++count == 3;
                                                                    });

你可能感兴趣的:(Predicates)