4

私はいくつかのタイミング テストを行っていましたが、そのテストの 1 つは関数を呼び出すさまざまな方法を比較することでした。さまざまな手段を使用して N 関数を呼び出しました。通常の関数呼び出し、仮想関数呼び出し、関数ポインター、boost::function を試しました。

gcc と -O3 最適化を使用して Linux でこれを行いました。

予想どおり、仮想呼び出しは通常の関数呼び出しよりも遅くなります。しかし驚くべきことは、boost::function が仮想呼び出しよりも 33% 遅くクロックインしたことです。

他の誰かがこれに気づきましたか?これがなぜなのか手がかりはありますか?

4

3 に答える 3

6

通常の関数は、可能であればコンパイラによってインライン化できますが、決してboost::functionインライン化することはできません。それが1つの大きな違いです。

2 番目の違いは、型消去boost::functionを実装することです。これは、実際の関数を呼び出すためにインダイレクションを使用することを意味します。最初に仮想関数を呼び出し、次に関数を呼び出すことを意味します。したがって、通常、(最小) 2 つの関数呼び出しが含まれます (そのうちの 1 つは です)。それは大きな違いです。virtual

したがって、この分析に基づいて、次のように推測できます (テスト コードを記述しなくても)。

slowest ------------------------------------------------------> fastest 
        boost::function < virtual function < regular function 
slowest ------------------------------------------------------> fastest

テストコードでは、これは実際に当てはまります。

std::function(C++11 以降で利用可能)にも当てはまることに注意してください。

于 2012-12-06T16:22:47.007 に答える
2

は、関数ポインタだけでなく、任意のオブジェクトのコピー全体を保持するboost::functionことができ、仮想上で呼び出すことができますoperator()

それがどのように機能するかを理解するのに役立ちます(説明のために)。

以下は、boost::function型トリックのおもちゃの実装です。

struct helper_base { virtual void do_it() = 0; };
template<typename Func>
struct helper:helper_base {
  Func func;
  helper(Func f):func(f) {}
  virtual void do_it() override { func(); }
};
struct do_something_later {
  boost::unique_ptr<helper_base> pImpl;
  template<typename Func>
  do_something_later( Func f ):pImpl(make_shared<helper<Func>>(f))
  {}
  void operator()() { (*pImpl).do_it(); }
private:
  do_something_later( do_something_later const& ); // deleted
  void operator=( do_something_later const& ); // deleted
};

ここで mydo_something_laterは任意のオブジェクト (Func) を取り、必要operator()に応じてそれを呼び出します。呼び出しているものの型を型消去ヘルパーでラップし、仮想関数を介してoperator()呼び出します。operator()

Functype は関数ポインターである場合もあれば、状態を持つファンクターである場合もあります。operator() でコピー可能なものは何でも公正なゲームです。のユーザーdo_something_laterに関する限り、バイナリ インターフェイスは 1 つしかありません。

boost::function(およびstd::function)基本的にこれと同じ手法を(多くの改善を加えて)使用して、可能なインターフェイスのセット全体を1つのインターフェイスに変換します。コストには、関数の呼び出しvirtual(または同等レベルの間接参照) が含まれます。

于 2012-12-06T16:42:31.990 に答える
0

観測された速度低下の本当の理由は、boost::function2 つの間接参照に加えてポインターをゼロと比較することです。このテストが省略された場合、呼び出しは仮想関数と同じくらい高速に実行されます (これには、vtable への 1 つのポインターと実際の関数への別の 2 つの間接参照も含まれます)。

于 2012-12-06T16:44:30.603 に答える