使用STL算法,传递函数指针或函子是否更好?

时间:2009-06-22 14:45:02

标签: c++ stl functor

这两种方法中哪一种更好,为什么?

方法1:

void fun(int i) {
  //do stuff
}

...
for_each(a.begin(), a.end(), fun);

方法2:

class functor {
public:
  void operator()(int i);
};

...
for_each(a.begin(), a.end(), functor());

编辑:应该用这种方式制定,在什么情况下上述方法之一优于另一种?

非常感谢!

6 个答案:

答案 0 :(得分:19)

Functors可以(并且)简单地内联 - 这不适用于常规函数指针。

因此,仿函数具有真正的性能优势,在紧密循环中可能是巨大的。此外,仿函数通常更易于组合,特别是使用STL更好:std::bind x 对函数指针不起作用。例如。

我讨厌它们如何使代码混乱,但是考虑到所有优点,我更喜欢它们而不是函数指针。

答案 1 :(得分:11)

为了清除对编译器可以内联的误解,一个足够好的编译器可以内联函数指针。它可以更容易地内联函数对象,因为有更多的静态信息可用。例如,指向不带参数并返回bool的函数的指针是bool(*)()类型,而仿函数有一个显式类型,即仿函数,模板实例化可以静态调用仿函数运算符,而不是而不必通过函数指针调用。

但实际上,主要是为编译器提供足够的信息以便有效地进行优化。

例如,Visual C ++ 2008,给出以下代码并进行完全优化:

#include "stdafx.h"
#include <algorithm>

const char print_me[]= "hello!";

class print_functor
{
public:
    void operator()(char c)
    {
        printf("%c", c);
    }
};

void print_function(char c)
{
    printf("%c", c);
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::for_each(print_me, print_me + sizeof(print_me)/sizeof(print_me[0]), print_functor());
    printf("\n");

    std::for_each(print_me, print_me + sizeof(print_me)/sizeof(print_me[0]), print_function);

    return 0;
}

完全内联std::for_each次调用。顺便说一下,在PC上,第一个for_each有一个不必要的lea ecx, [ecx]

答案 2 :(得分:7)

函数对象相对于函数指针的一大优点是,您可以更容易地在函数对象构造中绑定一些参数。

可能会这样做的仿函数的一个例子是

  class multiplyBy
  {
  private:
      int m_whatToMultiplyBy;
  public:
      multiplyBy(int whatToMultiplyBy) : 
          m_whatToMultiplyBy(whatToMultiplyBy)
      {
      }

      void operator()(int& i)
      {
          i = m_whatToMultiplyBy * i;
      }
  }


  ...

  // double the array
  for_each(a.begin(), a.end(), multiplyBy(2));

如果你可以使用提升,那么boost::bindboost::function可以很好地完成参数的“绑定”。

答案 3 :(得分:6)

我的观点 - #1更好,因为它更简单。

仅仅因为某物可以成为一个物体,并不意味着它应该是一个物体。我确信有些情况下仿函数有意义,但在大多数情况下可能没有必要。

答案 4 :(得分:1)

仿函数可以是more easily inlined,因此在性能很重要时可能需要考虑它。

答案 5 :(得分:1)

#1更容易声明函数
而#2的仿函数看起来更像是一个函数调用。

(有时候你不得不对c ++语法感到绝望)