11

これら 2 つの方法のどちらが優れているか、またその理由は何ですか?

方法 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());

編集:このように定式化する必要がありましたが、上記の方法のいずれかが他の方法よりも好ましいのはどのような状況ですか?

どうもありがとう!

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

関数ポインターに対する関数オブジェクトの大きな利点の 1 つは、関数オブジェクトの構築時にいくつかの引数をより簡単にバインドできることです。

これを行う可能性のあるファンクターの例は次のようになります

  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::bindおよびboost::functionを使用して行うことができます (boost が利用可能な場合)。

于 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 に答える