18

关于函数对象的维基百科文章中,它说这些对象在与for_each一起使用时具有性能优势,因为编译器可以“内联”它们。

我对这在这种情况下的确切含义有点模糊......或者我不好意思说的任何情况。谢谢你的帮助!

4

4 回答 4

16

for_each模板的最后一个参数是仿函数函子是可以使用()运算符(可能带有参数)“调用”的东西。根据定义,有两种不同的函子:

  1. 普通的非成员函数是函子。
  2. 具有重载运算符的类类型的对象()(所谓的函数对象)也是函子。

现在,如果你想使用一个普通函数作为 的函子for_each,它看起来像下面这样

inline void do_something(int &i) { /* do something */ }

int main() {
  int array[10];
  std::for_each(array, array + 10, &do_something);
}

在这种情况下,for_each模板是用 [deduced] arguments 实例化的<int *, void (*)(int &)>。请注意,在这种情况下,实际的函子值是&do_something作为函数参数传递的函数指针。从功能的角度来看,for_each这是一个运行时值。而且由于它是一个运行时值,因此不能内联对仿函数的调用。(就像在一般情况下不可能内联通过函数指针进行的任何调用)。

但是如果我们改用函数对象,代码可能如下所示

struct do_something {
  void operator()(int &i) { /* do something */ }
}; 

int main() {
  int array[10];
  std::for_each(array, array + 10, do_something());
}

在这种情况下,for_each模板是用 [deduced] arguments 实例化的<int *, do_something>。从内部对函子的调用for_each将被定向到do_something::operator(). 调用的目标是已知的并在编译时固定。由于目标函数在编译时是已知的,因此可以轻松内联调用。

在后一种情况下,我们当然也有一个运行时值作为参数传递给for_each. 它是do_something我们调用时创建的类的[可能是“虚拟”临时]实例for_each。但是这个运行时值对调用的目标没有影响(除非operator ()是虚拟的),所以它不会影响内联。

于 2010-02-08T23:35:02.557 回答
7

内联是编译器可以用函数本身的内容替换对函数的调用的过程。它要求编译器在编译时知道函数的内容。

如果传递了函数指针,编译器通常无法执行此操作。

于 2010-02-08T23:24:43.740 回答
3

内联只是意味着直接用该函数的主体替换对该函数的每个调用。

这是对小函数的优化,因为它减少了跳转到新函数然后返回的开销。

于 2010-02-08T23:23:47.400 回答
3

这意味着函数的定义(代码)可能会被复制并让您免于函数调用(这在某些系统上被认为是昂贵的)。考虑宏替换。

于 2010-02-08T23:23:54.437 回答