假设我有一个函数接受 std::function:
std::function
void callFunction(std::function<void()> x) { x(); }
我应该通过常量引用来传递 x吗? :
x
void callFunction(const std::function<void()>& x) { x(); }
这个问题的答案是否会根据函数的用途而改变?例如,如果它是一个类成员函数或构造函数,它将 std::function存储或初始化为一个成员变量。
如果您担心性能问题,并且没有定义虚拟成员函数,那么很可能根本就不应该使用 std::function。
使函数类型成为模板参数比 std::function允许更大的优化,包括内联函数逻辑。这些优化的效果可能会大大超过对如何传递 std::function的拷贝与间接关注。
更快:
template<typename Functor> void callFunction(Functor&& x) { x(); }
通常在 C + + 11中,传递 value/reference/const-reference 取决于您如何处理参数。
通过值 传递可以将参数移动到变量中(通常是类的成员变量) :
struct Foo { Foo(Object o) : m_o(std::move(o)) {} Object m_o; };
当你知道你的函数将移动它的参数,这是最好的解决方案,这样你的用户就可以控制他们如何调用你的函数:
Foo f1{Object()}; // move the temporary, followed by a move in the constructor Foo f2{some_object}; // copy the object, followed by a move in the constructor Foo f3{std::move(some_object)}; // move the object, followed by a move in the constructor
我相信你已经知道了(非)常量引用的语义,所以我就不赘述了。如果你需要我对此做更多的解释,尽管开口,我会更新。
如果希望获得性能,则在存储性能时按值传递。
假设您有一个名为“ run this in the UI thread”的函数。
std::future<void> run_in_ui_thread( std::function<void()> )
它在“ ui”线程中运行一些代码,然后在完成后发出 future信号。(在 UI 框架中非常有用,因为 UI 线程就是用来混淆 UI 元素的地方)
future
我们正在考虑两个签名:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A) std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
现在,我们可能会使用以下方法:
run_in_ui_thread( [=]{ // code goes here } ).wait();
它将创建一个匿名闭包(lambda) ,从中构造一个 std::function,将其传递给 run_in_ui_thread函数,然后等待它在主线程中完成运行。
run_in_ui_thread
在案例(A)中,std::function是直接从我们的 lambda 构造的,然后在 run_in_ui_thread中使用。波长是 moved 进入 std::function,所以任何可移动的状态都可以有效地进入它。
move
在第二种情况下,创建一个临时 std::function,lambda 是 moved,然后在 run_in_ui_thread中通过引用使用该临时 std::function。
到目前为止,一切都很好,他们俩的表现完全一样。除了 run_in_ui_thread将复制它的函数参数发送到 ui 线程执行!(它会在完成之前返回,所以它不能只使用对它的引用)。对于情况(A) ,我们简单地 move的 std::function到它的长期存储。在(B)情况下,我们被迫复制 std::function。
这个存储使得按值传递更加优化。如果存在存储 std::function副本的任何可能性,请通过值传递。否则,这两种方法大致相同: by-value 的唯一缺点是如果您使用相同的大容量 std::function,并且一个子方法接着一个子方法使用它。除此之外,move将与 const&一样高效。
const&
现在,如果我们在 std::function中有持久状态,那么这两者之间还有一些其他的区别。
假设 std::function用 operator() const存储一些对象,但是它也有一些 mutable数据成员需要修改(真粗鲁!).
operator() const
mutable
在 std::function<> const&情况下,修改后的 mutable数据成员将从函数调用中传播出去。在 std::function<>的情况下,他们不会。
std::function<> const&
std::function<>
这是一个相对奇怪的角落案件。
你想对待 std::function就像你会任何其他可能重量级,廉价的可移动类型。搬家成本低廉,复制成本高昂。