考虑一下,我使用std :: for_each和带有重载operator()的对象来累积一些关于向量内容的数据:
#include <iostream>
#include <vector>
#include <algorithm>
struct A{
int a;
A(): a(0){}
void operator()(int i) {
if(i) a++;
std::cout << "a:" << a << std::endl;
}
};
int main(int argc, char *argv[]) {
//test data
std::vector<int> vec;
vec.push_back(1);
vec.push_back(1);
vec.push_back(0);
//accumulator
A accum;
std::for_each(vec.begin(), vec.end(), accum);
std::cout << "non-zero elements:" << accum.a << std::endl;
return 0;
}
这outputs:
a:1
a:2
a:2
non-zero elements:0
为什么non-zero elements
为0?
答案 0 :(得分:6)
std::for_each()
没有通过引用获取第三个参数,因此创建了accum
的副本。
如果您向std::cout
添加A::A()
语句,则可以看到此行为。
请注意,您可以使用std::count_if()
解决此特定问题:
std::cout << "non-zero elements: "
<< std::count_if(vec.begin(),
vec.end(),
[](const int i) { return i != 0; })
<< std::endl;
答案 1 :(得分:2)
一般来说 1 标准库提供的算法不是通过引用来接受仿函数,而是按值,因此你不能“从外部”检查它的最终状态,因为仿函数你通过的是未受影响的。
幸运的是,for_each
在将仿函数应用于所有元素后返回该仿函数的副本,因此,您需要做的是:
accum = std::for_each(vec.begin(), vec.end(), accum);
请注意,由于这里涉及两个副本,通常最好使用副本很便宜的“琐碎”仿函数,如果编译器生成的仿函数不能,则提供复制构造函数非常重要。
然而,正如其他人所指出的,对于您正在执行的任务,有更适合的算法。
答案 2 :(得分:1)
标准库算法通常会复制他们的参数仿函数,因此对其状态的可能性将不可见。
你真的想在这里使用错误的算法。
for_each
旨在将操作应用于序列中的每个元素,仅此而已。
如果要迭代序列并累积某种数据,则应使用... std::accumulate
。 :)
该算法采用一个附加参数,即“状态”,并在算法完成后返回此状态。
答案 3 :(得分:0)
正如其他人所说,使用A
的不同实例,因为std::for_each
没有将仿函数作为参考。如果您slightly modify your code打印A::a
的地址
a:1 @0xbf86902c
a:2 @0xbf86902c
a:2 @0xbf86902c
non-zero elements:0 @0xbf869050