绑定函数(使用 Boost Bind)时是否有任何性能影响(正面或负面)?
2 回答
也许,也许不是。这取决于。
std::bind
(or also )的结果boost::bind
是所谓的“绑定表达式”,它具有由实现确定的不可知类型。这种类型是Callable,它可以转换为std::function
(or boost::function
) 的实例。
在内部,function
(可能)使用类型擦除来处理各种复杂的、有状态的“可调用对象”。在某些(尽管不一定是所有)情况下,这需要动态分配和虚拟分派。两者bind
和function
都是有状态的,因为它们存储绑定的参数。
结果是您应该尽可能避免将绑定表达式转换为function
对象。绑定表达式本身可能更便宜,并且您不应该害怕使用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
实用程序将它们传递给 areference_wrapper
这是一种非常轻量级的类型,用于存储指向对象的指针:
auto b = std::bind(func, std::ref(arg1), arg2, arg3);
当调用绑定函数时,每个绑定参数将作为左值传递给绑定函数(即没有完美转发):
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
诸如占位符和调用嵌套绑定表达式等特性,但这些并不影响性能,以上所有内容仍然适用。