Fast Delegate (その他) の背後にあるアイデアは、std::function の最適化に使用されていますか? 質問する

Fast Delegate (その他) の背後にあるアイデアは、std::function の最適化に使用されていますか? 質問する

次のようなものよりもオーバーヘッドが低い C++「デリゲート」の提案がありますboost::function

これらのアイデアのいずれかを の実装に使用してstd::function、 よりも優れたパフォーマンスを実現したことがありますか?とboost::functionのパフォーマンスを比較した人はいますか?std::functionboost::function

Intel 64ビットアーキテクチャ上のGCCコンパイラとlibstdc++について特に知りたい。ただし、他のコンパイラ (Clang など) に関する情報も歓迎します。

ベストアンサー1

libstdc++では、std::functionポインタ、関数ポインタ、またはメンバー関数へのポインタを格納するために適切なサイズとアラインメントのユニオン型を使用します。そのサイズとアラインメントで格納できる関数オブジェクトに対してはヒープ割り当てを回避します。しかし「位置不変」の場合のみ

/**
 *  Trait identifying "location-invariant" types, meaning that the
 *  address of the object (or any of its members) will not escape.
 *  Also implies a trivial copy constructor and assignment operator.
 */

コードはstd::tr1::function実装に基づいており、その部分は大幅に変更されていません。 を使用して簡素化できると思いますしstd::aligned_storage、より多くの型が位置不変として識別されるように特性を特殊化することで改善できると思います。

ターゲット オブジェクトの呼び出しは仮想関数呼び出しなしで行われ、型の消去はstd::function関数テンプレート特殊化のアドレスである単一の関数ポインターを格納することによって行われます。すべての操作は、格納されたポインターを介してその関数テンプレートを呼び出し、実行するように要求されている操作を識別する列挙型を渡すことによって行われます。つまり、vtable はなく、オブジェクトに格納する必要があるのは単一の関数ポインターのみです。

このデザインはオリジナルのboost::function作者によって提供されたもので、boostの実装に近いものだと思います。パフォーマンス何らかの根拠については、Boost.Function のドキュメントを参照してください。つまり、同じ人物による同様の設計であるため、 GCC のstd::functionが よりも高速である可能性はほとんどありません。boost::function

注意: our はstd::functionまだアロケータを使用した構築をサポートしていないため、必要な割り当てはすべて を使用して実行されますnew


メンバー関数とオブジェクトへのポインターを保持するのヒープ割り当てを避けたいという Emile のコメントに応えて、std::functionそれを実現するためのちょっとしたハックを紹介します (ただし、これは私から聞いたわけではありません ;-)

struct A {
  int i = 0;
  int foo() const { return 0; }
};

struct InvokeA
{
  int operator()() const { return a->foo(); }
  A* a;
};

namespace std
{
  template<> struct __is_location_invariant<InvokeA>
  { static const bool value = true; };
}

int main()
{
  A a;
  InvokeA inv{ &a };

  std::function<int()> f2(inv);

  return f2();
}

秘訣は、が の小さなオブジェクト バッファInvokeAに収まるほど小さく、特性の特殊化によってそこに保存しても安全であると指定されているため、 がそのオブジェクトのコピーをヒープ上ではなく直接保持することです。これにより、 へのポインタが存続する限り が存続する必要がありますが、のターゲットが であれば、いずれにせよそうなるでしょう。functionfunctionafunctionbind(&A::foo, &a)

おすすめ記事