私はそれがクローン化されたオブジェクトを毎回コピーします(正確には簡単ではない、ソースといくつかの実験の一遍読みから判断)を見つけることができるものから。関数がconst &によって引数をとる場合は不要かもしれませんが、一般にオブジェクトは関数によって変更される可能性があります。オブジェクトのコピーが高価な場合は、参照(boost::ref
またはが念頭に置かれます)でキャプチャするのは理にかなっていません。呼び出し元のオブジェクトが存在しない場合は、boost::shared_ptr
をキャプチャしてアダプタメソッドはスマートポインタを解凍し、someFunction
を呼び出しますか?
編集:実験では、boost::function
がコピーされるたびにそのオブジェクトをコピーするだけでなく、boost::bind
の中に数回もコピーされます。
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;
}
結果出力が続いているように:私は、GCC 4.6と-O2(および-std = C++ 0X)とMinGWの32下ブースト1.45を使用して、次のコードを使用して試験
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
したがって、コピーコンストラクタはf1のバインディングと代入のためにf2を1回と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つのコピーだけでオブジェクトをバインドします。だから、私は一般的にコードのリモートでパフォーマンスに影響を受けている部分でさえも、値ごとに少なくとも適度なコピーコストを持つものをキャプチャすることを避けるだろう。比較のGCCでstd::tr1::bind
とstd::bind
は、(コードが最初testcodeと基本的に同一である(スタンダード:: TR1 ::機能/ STD ::機能と連動して)はるかに良好に機能するだけで置き換えboost::
std::
それぞれstd::tr1::
有する:
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 inlinerにもっとやさしく書かれていて、インライン化して冗長コピーコンストラクタを取り除くと書いています。tr1::bind
はさらに最適化されてからboost::bind
になります。
もちろん、このような種類のテストでは、異なるコンパイルフラグ/コンパイラを使用するYMMV
経由で呼び出さ
g(const a &)
は、私がテストプログラムを書いて、それはあなたが関数オブジェクトをコピーするたびに呼び出されるん格納されたオブジェクトのコピーコンストラクタのように見えたときに呼び出されます。また、boost :: bindはコピーコンストラクタを11回呼び出します。 – Chris@Chris:Ok。だから、私のテストはよく知っておくべきではありませんでした。だからもし誰かがC++ 11を使うことができるのであればstd :: bindは遠くに行く方法です(私はちょうどlambdasを使うでしょうが)。 – Grizzly