理解STL中的函子 从《NM JouthIS》第5.9条引用“C++标准库”
for_each()的第二个调用使用相同的功能来添加第一个元素的值 每一个元素。它使用第一个元素初始化AddValue类型的临时函数对象 藏品目录:理解STL中的函子 从《NM JouthIS》第5.9条引用“C++标准库”,c++,stl,functor,function-object,C++,Stl,Functor,Function Object,for_each()的第二个调用使用相同的功能来添加第一个元素的值 每一个元素。它使用第一个元素初始化AddValue类型的临时函数对象 藏品目录: for_each (coll.begin(), coll.end(), AddValue (*coll. begin()) ) ; 添加第一个元素后,输出如下所示: 22 23 24 25 26 27 28 29 30 我不明白的是,在第二种情况下,为什么输出不是 22 34 35 36 37 38 39 40 41 意思是每次调用都会创
for_each (coll.begin(), coll.end(), AddValue (*coll. begin()) ) ;
添加第一个元素后,输出如下所示:
22 23 24 25 26 27 28 29 30
我不明白的是,在第二种情况下,为什么输出不是
22 34 35 36 37 38 39 40 41
意思是每次调用都会创建一个新的functor,还是每次调用都会使用该functor?是的,这就是您所说的。默认情况下,函子是按值传递的,因此它们在std::for_的代码中被复制。但是,您可以编写自己的std::for_版本,每个版本都明确声明希望通过引用传递functor。是。一个新的函子副本将为每个\u传递。您正在阅读的书对此进行了解释。表达式
AddValue(*coll.begin())
创建一个类AddValue
的临时对象。然后将该临时值传递给每个函数的for_each
然后调用对象的函数调用操作符-即,操作符()
-从coll.begin()
到coll.end()
的每个元素调用一次
从技术上讲,for_each
按值获取函子参数(不是引用),因此它实际上是在临时变量的副本上操作的,而不是临时变量本身。我相信函子像这样被复制的原因是为了使for_each
更通用
想象一个通过引用获取函子的实现。如果函子是一个右值(例如,如果它是从另一个函数返回的),则会中断:
当然,在这些情况下,算法可以通过常量引用获取函子(因为它们可以绑定到右值),但是函子必须是常量
唯一真正通用的解决方案是按值传递函子。然后它与常量、非常量、右值和左值函子一起工作。您的AddValue
构造函数接受int
,因此当您从*coll.begin()
构造它时,集合的第一个成员的值将用于初始化成员变量值
现在这是固定的(没有任何其他内容会修改值),因此每次从这个AddValue
对象或这个AddValue
对象的任何副本使用value
时,它仍将具有与初始化时相同的值
这是*coll.begin()
在构建第一个AddValue
对象时所具有的值,而不是*coll.begin()
可能已修改为的值。[Edit]我最初误解了作者的初衷。我改正了错误
对于每个(coll.begin(),coll.end(),
AddValue(*coll.begin())
之后,输出如下所示
添加第一个元素:
22 23 24 25 26 27 28 29 30
我不明白的是
第二种情况是为什么输出不是
22 34 35 36 37 38 39 40 41
意思是正在创建一个新的函子
对于每个调用或是否使用函子
每次通话
首先,不管for_是否复制了传入的函子,每个算法都是无关的。与此相关的是,您应该存储指向第一个元素的迭代器或指针,而不是指针对象。如果您这样做,并且每次都取消引用它,那么它应该会起作用
struct AddValue
{
const int* ptr;
explicit AddValue(const int* iptr): ptr(iptr) {}
void operator() (int& elem) const {elem += *ptr; }
};
int main()
{
vector<int> v;
for (int j=1; j <= 9; ++j)
v.push_back(j + 10);
for_each(v.begin(), v.end(), AddValue(&v[0]) );
// v will be [22 34 35 36 37 38 39 40 41]
}
struct AddValue
{
常数int*ptr;
显式AddValue(const int*iptr):ptr(iptr){}
void运算符()(int&elem)常量{elem+=*ptr;}
};
int main()
{
向量v;
对于(int j=1;j您能提供一个章节参考吗?我有点困惑。第8章更详细地解释了函数对象、谓词以及您可以依赖或不依赖的行为。例如,对于谓词,您永远无法确定您的谓词对象将被复制多少次。实际上,我对您的问题感到困惑。您为什么这样做除了22 34 35…?是的。但问题是为什么在每次调用中不重新创建新对象,重复使用同一对象?是为了某种并行性吗?在这种情况下,函子本身是否被复制是学术性的;它存储的是它构造时使用的值的面,而不是引用(或指针)它是用什么构造的,这会导致实际行为和Egon似乎期望的行为之间的差异。Egon-记住,对于_,每个函数都只是一个标准函数,而不是某种宏。一旦计算了它的输入值,它们就会传递给函数,并且是不可更改的。第三个参数t to for_each只是一个对象实例,它不是创建函子的lambda。for_each(a,b,c)不会(也不能)说,“对于[a,b]的每个元素,使用c的文本创建一个新的函子,并将元素传递给新的函子。”它说,“对于[a,b]范围内的每个元素,将元素传递给特定的函子实例c。”不过,在这种情况下,函子本身是否被复制并不重要,更重要的是它将值
存储为int
(即*coll.begin()
)的副本,而不是int&
,这意味着它的值在AddValue
构造时是固定的。
22 34 35 36 37 38 39 40 41
std::for_each(first, last, get_functor(...))
struct AddValue
{
const int* ptr;
explicit AddValue(const int* iptr): ptr(iptr) {}
void operator() (int& elem) const {elem += *ptr; }
};
int main()
{
vector<int> v;
for (int j=1; j <= 9; ++j)
v.push_back(j + 10);
for_each(v.begin(), v.end(), AddValue(&v[0]) );
// v will be [22 34 35 36 37 38 39 40 41]
}