Из того, что я могу найти (судя по беглому прочтению не совсем простого источника и некоторым экспериментам), оно будет каждый раз копировать клонированный объект. Это может быть ненужным в случае, если функция принимает аргумент через const &, но в целом объект может быть видоизменен функцией. Если объект дорогой для копирования, не имеет ли смысла захватывать его по ссылке (на ум приходит boost::ref
или boost::cref
) или, если исходный объект не существует в момент вызова, захватить boost::shared_ptr
и написать метод адаптера, который распаковывает смартпоинтер и вызывает someFunction
?
Редактировать: Из эксперимента он не только копирует конструкцию этого объекта всякий раз, когда копируется boost::function
, но также копирует несколько раз внутри boost::bind
. Я тестировал, используя следующий код, используя boost 1.45 под mingw 32 с 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
Итак, пять копий просто для привязки объекта. Поэтому я бы в целом избегал захвата всего, что имеет как минимум умеренную стоимость копирования на единицу, в любых, даже отдаленно чувствительных к производительности частях кода. В сравнении gccs std::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 для внутренних вызовов, либо написано так, что более удобно для inlineer gccs встроить некоторые в и устранить избыточные конструкторы копирования. tr1::bind
все еще лучше оптимизируется, чем boost::bind
, но все еще далеко от оптимального.
Конечно, как всегда, при такого рода тестах YMMV с разными флагами компиляции / компиляторами