私が見つけることができるものから (厳密には単純ではないソースといくつかの実験をざっと読んだことから判断すると)、毎回複製されたオブジェクトがコピーされます。const & で引数をとる関数の場合は不要かもしれませんが、一般的には関数によってオブジェクトが変更される可能性があります。boost::ref
オブジェクトをコピーするのにコストがかかる場合、参照によってキャプチャする (またはboost::cref
頭に浮かぶ) のは理にかなっていないでしょうか。または、元のオブジェクトが呼び出しの時点で存在しない場合は、a をキャプチャしboost::shared_ptr
てアダプタ メソッドを記述します。 smartpointer を解凍してsomeFunction
?
編集:実験から、 がコピーされるたびにそのオブジェクトをコピーするだけでなくboost::function
、 内で数回コピーしますboost::bind
。gcc 4.6 および -O2 (および -std=c++0x) で mingw 32 の下でブースト 1.45 を使用して、次のコードを使用してテストしました。
struct foo_bar {
std::vector<int> data; //possibly expensive to copy
foo_bar()
{ std::cout<<"default foo_bar "<<std::endl; }
foo_bar(const foo_bar& b):data(b.data)
{ std::cout<<"copy foo_bar "<<&b<<" to "<<this<<std::endl; }
foo_bar& operator=(const foo_bar& b) {
this->data = b.data;
std::cout<<"asign foo_bar "<<&b<<" to "<<this<<std::endl;
return *this;
}
~foo_bar(){}
};
void func(const foo_bar& bar) { std::cout<<"func"<<std::endl;}
int main(int, char*[]) {
foo_bar fb;
boost::function<void()> f1(boost::bind(func, fb));
std::cout<<"Bind finished"<<std::endl;
boost::function<void()> f2(f1);
std::cout<<"copy finished"<<std::endl;
f1();
f2();
return 0;
}
結果の出力は次のとおりです。
default foo_bar
copy foo_bar 0x28ff00 to 0x28ff10
copy foo_bar 0x28ff10 to 0x28ff28
copy foo_bar 0x28ff28 to 0x28ff1c
copy foo_bar 0x28ff1c to 0x28ff34
copy foo_bar 0x28ff34 to 0x28fed4
copy foo_bar 0x28fed4 to 0x28fee4
copy foo_bar 0x28fee4 to 0x28fef4
copy foo_bar 0x28fef4 to 0x28fe14
copy foo_bar 0x28fe14 to 0x28fe24
copy foo_bar 0x28fe24 to 0x28fe34
copy foo_bar 0x28fe34 to 0x6a2c7c
Bind finished
copy foo_bar 0x6a2c7c to 0x6a2c94
copy finished
func
func
そのため、コピー コンストラクターは、f2 の作成のために 1 回呼び出され、f1 へのバインディングと代入のために 11 回呼び出されました。最初のオブジェクトがスタック上に作成され、コピーのアドレスがそれに非常に近く、わずかに増加しているため、バインド プロセスは多くの関数を経由しているように見えますが、この場合、コンパイラはインライン化しません。オブジェクトを値で渡します。boost::bind
結果をどこにも保存せずに使用する:
int main(int, char*[]) {
foo_bar fb;
boost::function<void()> f1(boost::bind(func, fb));
return 0;
}
default foo_bar
copy foo_bar 0x28ff00 to 0x28ff10
copy foo_bar 0x28ff10 to 0x28ff28
copy foo_bar 0x28ff28 to 0x28ff1c
copy foo_bar 0x28ff1c to 0x28ff34
copy foo_bar 0x28ff34 to 0x28fef4
したがって、オブジェクトをバインドするためだけに 5 つのコピーが必要です。したがって、コードのパフォーマンスに敏感な部分であっても、値あたりのコピーコストが少なくとも中程度のものをキャプチャすることは一般的に避けます。比較すると、gccsstd::tr1::bind
とstd::bind
パフォーマンスははるかに優れています (std::tr1::function / std::function と組み合わせて) (コードは基本的に最初のテストコードと同じで、boost::
それぞれをstd::tr1::
次のように置き換えますstd::
。
std::tr1::bind with std::tr1::function:
default foo_bar
copy foo_bar 0x28ff10 to 0x28ff28
copy foo_bar 0x28ff28 to 0x28ff34
copy foo_bar 0x28ff34 to 0x28ff04
copy foo_bar 0x28ff04 to 0x652c7c
Bind finished
copy foo_bar 0x652c7c to 0x652c94
copy finished
func
func
std::bind with std::function:
default foo_bar
copy foo_bar 0x28ff34 to 0x28ff28
copy foo_bar 0x28ff28 to 0x3c2c7c
Bind finished
copy foo_bar 0x3c2c7c to 0x3c2c94
copy finished
func
func
std::bind
内部呼び出しのために const ref によって渡されるか、gccs インライン化に適した方法で記述され、一部をインライン化し、冗長なコピー コンストラクターを排除すると仮定します。tr1::bind
その後も最適化されますがboost::bind
、最適にはほど遠いです。
もちろん、いつものように、さまざまなコンパイル フラグ/コンパイラを使用した YMMV のようなテストを行います。