我应该通过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被move
到std::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引用的语义,所以我不会重点介绍。 如果您需要我添加更多关于此的解释,只需要问我即将更新。