我应该通过const参考传递一个std ::函数吗?

比方说,我有一个函数,它需要一个std::function

 void callFunction(std::function<void()> x) { x(); } 

我应该通过由const参考x

 void callFunction(const std::function<void()>& x) { x(); } 

这个问题的答案是否会根据函数做什么而改变? 例如,如果它是一个类成员函数或构造函数,它将std::function存储或初始化为成员variables。

如果你想要performance的话,如果你正在存储它,那么通过价值传递。

假设你有一个叫“在UI线程中运行”的函数。

 std::future<void> run_in_ui_thread( std::function<void()> ) 

它在“ui”线程中运行一些代码,然后在完成时指示future 。 (在用户界面线程是你应该混淆UI元素的UI框架中有用)

我们有两个签名,我们正在考虑:

 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(); 

这将创build一个匿名闭包(lambda),构造一个std::function ,将其传递给run_in_ui_thread函数,然后等待它在主线程中完成运行。

在(A)的情况下, std::function直接从我们的lambda构造,然后在run_in_ui_thread 。 lambda被movestd::function ,所以任何可移动的状态都被有效地传入。

在第二种情况下,创build一个临时std::function ,lambda move d移入它,然后在run_in_ui_thread通过引用使用临时std::function

到目前为止,这么好 – 他们两个performance一致。 除了run_in_ui_thread将要做它的函数参数的副本发送到UI线程执行! (它会在它完成之前返回,所以它不能只使用它的引用)。 对于情况(A),我们只需move std::function移到其长期存储中。 在(B)的情况下,我们被迫复制std::function

那家商店使价值传递更加优化。 如果有可能存储std::function的副本, std::function值传递。 否则,任何一种方法都大致相同:唯一的缺点是如果你正在使用同样庞大的std::function并且有一个接一个的子方法使用它。 除此之外,一个move将像一个const&一样高效。

现在,如果我们在std::function有持久化状态,那么大多数情况下都会有一些其他的区别。

假设std::function用一个operator() const存储某个对象,但是它也有一些mutable修改的数据成员(多么粗鲁!)。

std::function<> const& case中,被修改的mutable数据成员将传播出函数调用。 在std::function<>情况下,他们不会。

这是一个比较奇怪的angular落案例。

你想要像对待任何其他可能重量较轻,价格便宜的types一样对待std::function 。 移动很便宜,复制可能很昂贵。

如果你担心性能,而你没有定义一个虚拟成员函数,那么你很可能根本不应该使用std::function

使函数types为模板参数允许比std::function更优化,包括内联函子逻辑。 这些优化的效果可能大大超过了如何传递std::function的copy-vs-indirection问题。

更快:

 template<typename Functor> void callFunction(Functor&& x) { x(); } 

和往常一样,在C ++ 11中,传递值/引用/常量引用取决于你对你的参数做了什么。 std::function没有什么不同。

按值传递允许您将参数移动到variables(通常是类的成员variables)中:

 struct Foo { Foo(Object o) : m_o(std::move(o)) {} Object m_o; }; 

当你知道你的函数会移动它的参数时,这是最好的解决scheme,这样你的用户可以控制他们如何调用你的函数:

 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 

我相信你已经知道了(非)const引用的语义,所以我不会重点介绍。 如果您需要我添加更多关于此的解释,只需要问我即将更新。