次のようなものよりもオーバーヘッドが低い C++「デリゲート」の提案がありますboost::function
。
これらのアイデアのいずれかを の実装に使用してstd::function
、 よりも優れたパフォーマンスを実現したことがありますか?とboost::function
のパフォーマンスを比較した人はいますか?std::function
boost::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
に収まるほど小さく、特性の特殊化によってそこに保存しても安全であると指定されているため、 がそのオブジェクトのコピーをヒープ上ではなく直接保持することです。これにより、 へのポインタが存続する限り が存続する必要がありますが、のターゲットが であれば、いずれにせよそうなるでしょう。function
function
a
function
bind(&A::foo, &a)