c++ - std::function - 值与参考参数
问题描述
std::function
带有值参数的类型与带有 const 引用值参数的类型之间有什么实际区别吗?考虑以下代码:
auto foo = [] (VeryBigType i) {
};
auto bar = [] (const VeryBigType& i) {
};
std::function<void(VeryBigType)> a;
a = foo;
a = bar;
std::function<void(const VeryBigType&)> b;
b = foo;
b = bar;
此代码编译没有问题并且运行良好。我知道按值传递与按引用传递有性能差异,因此foo
会bar
表现不同。但是根据std::function
模板类型有什么不同吗?例如,
std::function<void(VeryBigType)>(bar)
vs之间是否存在任何实现和/或行为和/或性能差异,std::function<void(const VeryBigType&)>(bar)
或者这些构造是等效的?
解决方案
cppreference 说有std::function<R(Args...)>::operator()
签名
R operator()(Args... args) const;
f
并且它基本上通过调用存储的可调用对象f(std::forward<Args>(args)...)
。性能特征取决于模板参数和 lambda 的参数类型,我认为只查看可能发生的一切会很有帮助。在您的情况下,您有 2std::function
种类型、2 个可调用对象和 3 个可能的参数值类别,为您提供 12 种可能性。
std::function<void(VeryBigType)> f = [](VeryBigType i) { }
如果你用左值调用它,比如
VeryBigType v; f(v);
这将复制
v
到 的参数中operator()
,然后operator()
将一个右值传递给 lambda,这会将值移动到i
. 总成本:1份+1招如果你用纯右值调用它,比如
f(VeryBigType{});
然后这会将纯右值具体化为 的参数
operator()
,然后将一个右值传递给 lambda,它会将其移动到i
. 总成本:1 步如果你用一个 xvalue 来调用它,比如
VeryBigType v; f(std::move(v));
这将移动
v
到 的参数中operator()
,这会将右值传递给 lambda,然后将其再次移动到i
. 总成本:2 步。
std::function<void(VeryBigType)> f = [](VeryBigType const &i) { }
如果您使用左值调用 this,则 this 将复制一次到 的参数中
operator()
,然后 lambda 将获得对该参数的引用。总成本:1份。如果您使用纯右值调用它,这会将其具体化为 的参数
operator()
,该参数会将对该参数的引用传递给 lambda。总成本:没有。如果你用一个 xvalue 调用它,这会将它移动到 的参数中
operator()
,这会将对该参数的引用传递给 lambda。总成本:1 步。
std::function<void(VeryBigType const&)> f = [](VeryBigType i) { }
- 如果您使用左值或 xvalue(即使用左值)调用它,
operator()
将收到对它的引用。如果你用纯右值调用它,它将被具体化为一个临时值,并operator()
会收到对它的引用。无论如何,对 lambda 的内部调用将始终复制。总成本:1份。
- 如果您使用左值或 xvalue(即使用左值)调用它,
std::function<void(VeryBigType const&)> f = [](VeryBigType const &i) { }
- 同样,无论你用什么称呼它,
operator()
都只会收到对它的引用,而 lambda 只会收到相同的引用。总成本:没有。
- 同样,无论你用什么称呼它,
那么,我们学到了什么?如果 thestd::function
和 lambda 都采用引用,则可以避免任何无关的复制和移动。尽可能使用它。然而,将一个按值的 lambda 放在一个按const
--lvalue-referencestd::function
中是一个坏主意(除非你必须这样做)。本质上,左值引用“忘记”了参数的值类别,并且始终复制 lambda 的参数。将 by-- const
lvalue-reference lambda 放入 by-valuestd::function
在性能方面非常好,但只有在调用其他需要 by-value 的代码时才需要这样做std::function
,否则按引用std::function
实现同样的东西,但复制和移动更少。将一个按值 lambda 放在一个按值内std::function
比放入一个 -const
-lvalue-reference lambda 在其中,由于所有调用中的额外移动。最好改为通过右值引用获取 lambda 的参数,这与通过const
左值引用获取它几乎相同,只是你仍然可以改变参数,就像你无论如何都按值获取它一样.
std::function
TL;DR:模板参数中的按值和右值引用参数应对应于const
您放入std::function
. 类型中的按左值引用参数应对应于 lambda 中的按左值引用参数。其他任何东西都会产生额外的副本或移动,并且只应在需要时使用。
推荐阅读
- django - Django 无法识别已删除/添加的文件
- javascript - scrollintoview() 被粘性导航栏阻止
- ios - UITableView 单元格计数不足
- php - 如何在不使用 <--more--> 的情况下将 wordpress the_content 拆分为 3 列
- javascript - 在 FireFox 中未触发 Ember 操作
- html - 以不同的分辨率在一行上输入收音机和输入文本
- android - 如何对浮点数数组求和
- php - $_POST 在服务器上返回 null,但在 mamp localhost 上工作正常
- mysql - 按2个字段组合分组,然后按每个组的总和排序,多个注释django
- opennms - Opnenms UI 错误 - HTTP 错误:503