question about function object

I have a code as following:

#include <iostream>
#include <algorithm>
#include <list>
using namespace std;

//the class Nth is a predicates
class Nth{
    private:
         int nth;
         int count;
    public:
         Nth(int n):nth(n),count(0){}
         bool operator()(int){
             return ++count == nth;
        }
};

int main()
{
       list<int> lst;
 
       for(int i=1;i<10;i++)
           lst.push_back(i);

       copy(lst.begin(),lst.end(),ostream_iterator<int>(cout," "));
       cout<<endl;

       list<int>::iterator pos = remove_if(lst.begin(),lst.end(),Nth(3));
       lst.erase(pos,lst.end());

       copy(lst.begin(),lst.end(),ostream_iterator<int>(cout," "));
       cout<<endl;
} 

the output is:
1 2 3 4 5 6 7 8 9
1 2 4 5 7 8 9
Not as I expect:
1 2 3 4 5 6 7 8 9
1 2 4 5 6 7 8 9
The book explained:
This happens because the usual implementation of the algorithm copies the predicate internally during the algorithm:

template<class ForwIter,class Predicate>
ForwIter std::remove_if(ForwIter beg,ForeIter end,Predicate op)
{
       ForwIter pos = find_if(beg,end,op);
       if(pos == end)
            return beg;
       else{
            ForwIter next = beg;
            return remove_copy_if(++next,end,beg,op);
       }
}

and it says it is possible to avoid this surprise behavior like this:

template<class ForwIter,class Predicate>
ForwIter std::remove_if(ForwIter beg,ForeIter end,Predicate op)
{
       while(beg != end && !op(*beg))
            beg++;
       if(pos == end)
            return beg;
       else{
            ForwIter next = beg;
            return remove_copy_if(++next,end,beg,op);
       }
}

I don't know what the difference between the two implementations is.I think i was able to understand the first one,but why the second one works fine?I thought they were the same.Any help will be appreciated.

template<class ForwIter,class Predicate>
ForwIter std::remove_if(ForwIter beg,ForeIter end,Predicate op)
{
       //A copy of "op" is created inside find_if effectively
       // as a local variable.  This is how pass-by-value works, rather
       // than pass-by-reference.  changes made in find_if aren't reflected
       // in our original "op".
       ForwIter pos = find_if(beg,end,op);
       if(pos == end)
            return beg;
       else{
            ForwIter next = beg;
            return remove_copy_if(++next,end,beg,op);
       }
}
template<class ForwIter,class Predicate>
ForwIter std::remove_if(ForwIter beg,ForeIter end,Predicate op)
{
       // Here we use 'op' directly, not a copy of it.
       while(beg != end && !op(*beg))
            beg++;
       if(pos == end)
            return beg;
       else{
            ForwIter next = beg;
            //Now that we've modified it in the manner we wanted,
            // we pass the modified version into remove_copy_if.
            return remove_copy_if(++next,end,beg,op);
       }
}

This is just how pass-by-value works, things get copies. A simpler example:

#include <stdio.h>

// val is effectively a local variable
void pass_by_value(int val)
{
        val++;
}

// val is effectively the same variable you passed it
// This style of reference isn't found in C, just C++
void pass_by_reference(int &val)
{
        val++;
}

// Another way of pass-by-reference.
void pass_by_pointer(int *val)
{
        (*val)++;
}

int main(void)
{
        int q=5;
        printf("q=%d\n", q);
        pass_by_value(q);
        printf("q=%d\n", q);
        pass_by_reference(q);
        printf("q=%d\n", q);
        pass_by_pointer(&q);
        printf("q=%d\n", q);
        return(0);
}

should print

q=5
q=5
q=6
q=7
1 Like

Thanks for your post,it's clear now.And i realized that i misunderstand the remove_copy_if,this algorithm Copies the values of the elements in the range [first,last) to the range positions beginning at result, except those for which pred is true, which are not copied.I missed the word "Not":wall:.Thank you again!

1 Like