関数をバインドする場合 (Boost Bind を使用)、パフォーマンスに (正または負の) 影響はありますか?
2 に答える
たぶん、そうではないかもしれません。場合によります。
std::bind
(または)の結果boost::bind
は、いわゆる「バインド式」であり、実装によって決定される不明なタイプを持ちます。このタイプはCallableであり、 (または)のインスタンスに変換できます。std::function
boost::function
内部的には、function
型消去を使用して、さまざまな複雑でステートフルな「呼び出し可能オブジェクト」を処理します。これには、動的割り当てと仮想ディスパッチが必要になる場合があります(必ずしもすべてではありません)。bind
とはfunction
、バインドされた引数を格納するため、ステートフルです。
function
結果として、可能であれば、バインド式をオブジェクトに変換することは避けてください。バインド式自体は安価な場合があり、使用することを恐れないでくださいbind
(たとえば、メンバー関数ポインターをインスタンスと引数にバインドする場合)。bind
自由に使用できfunction
ますが、呼び出し可能なエンティティの異種コレクションを本当に管理する必要がある場合にのみ変換してください。
次に2つの典型的な例を示します。
悪い; これを避けてください:
std::function<int(bool, char)> f = std::bind(&Foo::bar, x, 12);
void do_something(std::function<int()> func, int & acc)
{
acc += func();
}
より良い; これを好む:
auto f = std::bind(&Foo::bar, x, 12); // unknowable type, but perfectly fine
template <typename F>
void do_something(F && func, int & acc) // can deduce unknowable types
{
acc += func();
}
boost::bind
std::bind
関数オブジェクトを含む各引数のコピーが返されるオブジェクトに含まれるように、引数をコピーします。これらの引数をコピーするのにコストがかかる場合は、それらを に渡すのにコストがかかりますstd::bind
。
すべての引数のタプルを作成するのと同じように考えることができます。
auto b = std::bind(func, arg1, arg2, arg3);
パフォーマンスは次のものとほぼ同等である必要があります。
auto b = std::make_tuple(func, arg1, arg2, arg3);
引数をコピーしたくない場合は、ユーティリティを使用して、オブジェクトへのポインターを格納する非常に軽量な型に引数ref
を渡します。reference_wrapper
auto b = std::bind(func, std::ref(arg1), arg2, arg3);
バインドされた関数を呼び出すと、バインドされた各引数が左辺値としてバインドされた関数に渡されます (つまり、完全な転送ではありません)。
b(); // equiv to std::get<0>(b)(std::get<1>(b), std::get<2>(b), std::get<3>(b))
関数が引数を値で受け取る場合、バインドされた引数は関数の引数にコピーされます。それは高価になる可能性がありますが、関数を直接呼び出すか、結果内で呼び出すかはまったく同じですstd::bind
...バインド式ではなく、呼び出される関数のプロパティです。
したがって、使用の唯一のオーバーヘッドはboost::bind
、バインドされた引数の最初のコピーにあります。これは、引数を移動してコピーを回避することで制御できます。
auto b = std::bind(func, std::move(arg1), arg2, arg3);
または参照渡し:
auto b = std::bind(func, std::ref(arg1), arg2, arg3);
上記の説明では、bind
プレースホルダーやネストされたバインド式の呼び出しなどの機能は無視されていますが、これらはパフォーマンスに影響せず、上記のすべてが適用されます。