我应该通过const引用传递std::函数吗
Should I pass an std::function by const-reference?
假设我有一个函数,它接受std::function
:
void callFunction(std::function<void()> x)
{
x();
}
我应该改为通过常量引用传递x
吗?:
void callFunction(const std::function<void()>& x)
{
x();
}
这个问题的答案是否会随着函数的作用而改变?例如,如果是将std::function
存储或初始化为数据成员的成员函数或构造函数。
如果您想要性能,请在存储时传递值。
假设您有一个名为"在UI线程中运行此"的函数。
std::future<void> run_in_ui_thread( std::function<void()> )
它在"ui"线程中运行一些代码,然后在完成时向future
发出信号。(在UI框架中很有用,因为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();
它将创建一个匿名闭包(lambda),从中构造一个std::function
,将其传递给run_in_ui_thread
函数,然后等待它在主线程中完成运行。
在情况(A)中,std::function
直接由我们的lambda构造,然后在run_in_ui_thread
中使用。λ是move
d到std::function
,所以任何可移动的状态都被有效地携带到其中
在第二种情况下,创建一个临时std::function
,lambda是其中的move
d,然后该临时std::function
在run_in_ui_thread
内通过引用使用。
到目前为止,一切都很好——他们两个的表现完全一样。除了run_in_ui_thread
要复制它的函数参数发送到ui线程执行!(它将在使用它之前返回,因此不能仅使用对它的引用)。对于情况(A),我们简单地将move
和std::function
放入其长期存储中。在情况(B)中,我们被迫复制std::function
。
这家商店使价值传递更加优化。如果您可能正在存储std::function
的副本,请传递值。否则,任何一种方法都大致相同:按值计算的唯一缺点是,如果你使用相同的庞大的std::function
,并有一个又一个子方法使用它。除此之外,move
的效率将与const&
一样高。
现在,如果我们在std::function
中有持久状态,这两者之间还有一些其他的差异。
假设std::function
存储了一些带有operator() const
的对象,但它也有一些mutable
数据成员要修改(太粗鲁了!)。
在std::function<> const&
的情况下,修改后的mutable
数据成员将传播到函数调用之外。在std::function<>
的情况下,他们不会。
这是一个相对奇怪的角落案例。
你想像对待任何其他可能重量重、价格低廉的活字一样对待std::function
。搬家很便宜,复印也很贵。
如果您担心性能,并且没有定义虚拟成员函数,那么很可能根本不应该使用std::function
。
将函子类型设置为模板参数可以实现比std::function
更大的优化,包括内联函子逻辑。这些优化的效果可能会大大超过关于如何传递std::function
的复制与间接关注。
更快:
template<typename Functor>
void callFunction(Functor&& x)
{
x();
}
在C++11中,传递值/reference/const引用取决于您对参数的处理方式。CCD_ 34也不例外。
通过值传递可以将参数移动到变量(通常是类的成员变量)中:
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
我相信你已经知道(非)const引用的语义了,所以我就不赘述了。如果你需要我对此补充更多解释,只要问一下,我就会更新。
- 使用std::函数映射对象方法
- 可组合的lambda/std::函数与std::可选
- 当使用透明的std函数对象时,我们还需要写空的尖括号吗
- std::函数常量正确性未遵循
- 具有变量Number of Arguments的std::函数的矢量
- 从类型std::函数传递变量失败,尽管调用方期望的类型完全相同
- 如何调用存储在指向"std::函数"的指针中的 lambda?
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 如何将类 1 的 std::函数绑定到类 2 的函数?
- 如何制作可以接受任何类型的参数的 std::函数和 lambda
- 如何将 STL 队列推送函数绑定到 std::函数?
- std::函数不起作用,但普通的旧函数指针可以 - 为什么?
- 获取 std::函数以推断按引用传递/按值传递
- std::bind 和 std::函数术语不值为接受 0 个参数?
- 从其存储的回调中删除 std::函数是否安全
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 创建一个带有 lambda 的 std::函数,而不知道函数的参数
- std::函数的解释
- 在调用过程中删除 std::函数