Есть ли какое-либо влияние на производительность (положительное или отрицательное) при связывании функций (используя Boost Bind)?
Может быть, не может быть. Это зависит.
Результат std::bind
(или также boost::bind
) — это так называемое «выражение привязки», которое имеет непознаваемый тип, определяемый реализацией. Этот тип подлежащий выкупу, и это конвертируемый к примеру std::function
(или же boost::function
).
Внутренне function
(может) использовать стирание типа для обработки различных сложных, вызываемых состоянием «вызываемых объектов». Это влечет за собой динамическое распределение и виртуальную диспетчеризацию в некоторых (хотя и не обязательно во всех) случаях. И то и другое bind
а также function
с состоянием, так как они хранят связанные аргументы.
В результате вы должны избегать преобразования выражения связывания в function
возражать, если это возможно. Само выражение bind может быть дешевле, и вы не должны бояться использовать bind
(например, при привязке указателей на функции-члены к экземплярам и аргументам). использование bind
свободно, но преобразование в function
только если вам действительно нужно управлять разнородной коллекцией вызываемых объектов.
Вот два типичных примера:
Плохой; Избегайте этого:
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);
При вызове связанной функции каждый из связанных аргументов будет передан связанной функции в виде lvalues (т.е. без идеальной пересылки):
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
такие как заполнители и вызов вложенных выражений связывания, но они не влияют на производительность, и все вышеперечисленное все еще применяется.