在下面的 C++ STL 程序中,我定义了一个第 N 个仿函数,如果它在第 n 次被撤销,它返回 true。我将它转换为通用算法 remove_if,我得到了一些奇怪的东西。
代码:
#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 : ");
}
打印.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;
}
我在 Microsoft Visual Studio 2008 中运行它并得到结果: 它删除了我不想要的元素 3 和 6。我以为只会删除 3。 有人可以为我翻译吗?非常感谢。
最佳答案
来自 C++ 标准库:Nicolai M. Josuttis 的教程和引用
发生这种情况是因为算法的通常实现在算法期间在内部复制谓词:
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);
}
}
该算法使用 find_if() 查找应删除的第一个元素。但是,它随后使用传递的谓词 op 的拷贝来处理剩余的元素(如果有的话)。这里再次使用了原来状态的Nth,同时也去掉了剩余元素中的第三个元素,其实就是第六个元素。
此行为不是错误。该标准没有指定算法在内部复制谓词的频率。因此,要获得 C++ 标准库的保证行为,您不应传递其行为取决于复制或调用频率的函数对象。因此,如果您为两个参数调用一元谓词并且两个参数相等,那么谓词应该总是产生相同的结果。也就是说,谓词不应因调用而改变其状态,并且谓词的拷贝应具有与原始状态相同的状态。为确保不能因函数调用而改变谓词的状态,应将 operator() 声明为常量成员函数。
关于c++ - 使用仿函数作为谓词的 C++ STL 程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10267944/