11

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

方法一:

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

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

方法二:

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

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

编辑:应该这样制定,在什么情况下上述方法中的一种比另一种更可取?

非常感谢!

4

6 回答 6

20

函子可能(并且将会)被简单地内联——这不适用于常规函数指针。

因此,仿函数具有真正的性能优势,这在紧密循环中可能是巨大的。此外,函子通常更容易组合,特别是与 STL 一起玩得更好:std::bindx例如,不适用于函数指针。

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

于 2009-06-22T14:54:35.703 回答
11

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

但在实践中,主要是为编译器提供足够的信息以进行有效优化。

例如,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].

于 2009-06-22T18:17:49.873 回答
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,这种参数的“绑定”可以很好地完成。

于 2009-06-22T14:49:57.617 回答
6

我的意见 - #1 更好,因为它更简单。

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

于 2009-06-22T14:48:17.480 回答
1

仿函数可以更容易地内联,因此当性能很重要时,它可能是一个需要考虑的因素。

于 2009-06-22T14:49:42.827 回答
1

#1 更容易声明函数
,而 #2 仿函数看起来更像函数调用。

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

于 2009-06-22T14:50:29.690 回答