从我能找到的(从对不完全简单的来源和一些实验的粗略阅读来看)它每次都会复制克隆的对象。如果函数通过 const & 获取参数,则可能没有必要,但通常该对象可能会被函数突变。boost::ref
如果对象的复制成本很高,那么通过引用(或boost::cref
想到)捕获它是否有意义,或者,如果原始对象在调用点不存在,则捕获boost::shared_ptr
并编写一个适配器方法,该方法解压智能指针并调用someFunction
?
编辑:从实验来看,它不仅会在复制时复制该对象boost::function
,而且还会在boost::bind
. 我使用以下代码在 mingw 32 下使用 boost 1.45 和 gcc 4.6 和 -O2 (和 -std=c++0x)进行了测试:
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,并调用了 11 次以绑定和分配给 f1。由于第一个对象是在堆栈上创建的,并且副本的地址非常接近并且略有增加,因此绑定过程似乎经历了很多函数,在这种情况下编译器没有内联,每个按值传递对象。直接使用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
所以五个副本只是为了绑定对象。因此,我通常会避免在代码的任何远程性能敏感部分中捕获至少具有中等复制成本的任何内容。相比之下 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 测试