In the following C++ STL program,I define a functor Nth and it returns true if it is revoke in the nth time.And I transform it to generic algorithm remove_if,I get something strange.
The code:
#include <iostream>
#include <list>
#include <algorithm>
#include "print.hpp"
using namespace std;
class Nth{
private:
int nth,ncount;
public:
Nth(int n):nth(n),ncount(0){}
bool operator()(int)
{
return ++ncount == nth;
}
};
int main()
{
list<int> col;
for (int i = 1;i <=9 ;++i)
{
col.push_back(i);
}
PRINT_ELEMENTS(col,"col : ");
list<int>::iterator pos;
pos = remove_if(col.begin(),col.end(),
Nth(3));
col.erase(pos,col.end());
PRINT_ELEMENTS(col,"nth removed : ");
}
print.hpp:
#include <iostream>
template <class T>
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
typename T::const_iterator pos;
std::cout << optcstr;
for (pos=coll.begin(); pos!=coll.end(); ++pos) {
std::cout << *pos << ' ';
}
std::cout << std::endl;
}
I run it in Microsoft Visual Studio 2008 and I get the result: It deletes the elements 3 and 6 that is not I want.I thought only 3 would be deleted. Could someone interpret for me?Thanks a lot.
From The C++ Standard Library: A Tutorial and Reference By Nicolai M. Josuttis
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, ForwIter end,
Predicate op)
{
beg = find_if(beg, end, op);
if (beg == end) {
return beg;
}
else {
ForwIter next = beg;
return remove_copy_if(++next, end, beg, op);
}
}
The algorithm uses find_if() to find the first element that should be removed. However, it 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 it also removes the third element of the remaining elements, which is in fact the sixth element.
This behavior is not a bug. The standard does not specify how often a predicate might be copied internally by an algorithm. Thus, to get the guaranteed behavior of the C++ standard library you should not pass a function object for which the behavior depends on how often it is copied or called. Thus, if you call a unary predicate for two arguments and both arguments are equal, then the predicate should always yield the same result. That is, a predicate should not change its state due to a call, and a copy of a predicate should have the same state as the original. To ensure that you can't change the state of a predicate due to a function call, you should declare operator () as constant member function.
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