std::function
之间是否有任何实际差异?对于具有值参数的类型与对值参数的常量引用?考虑以下代码:
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)
对比 std::function<void(const VeryBigType&)>(bar)
或者这些结构是等效的?
最佳答案
cppreference says那个std::function<R(Args...)>::operator()
有签名
R operator()(Args... args) const;
并且它调用存储的可调用
f
基本上由 f(std::forward<Args>(args)...)
.性能特征取决于模板参数和 lambda 的参数类型,我认为看到可能发生的一切会很有帮助。就您而言,您有 2 std::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 次移动 VeryBigType v;
f(std::move(v));
这将移动
v
进入 operator()
的论点,它将右值传递给 lambda,它将再次将其移动到 i
.总成本:2 次移动。 std::function<void(VeryBigType)> f = [](VeryBigType const &i) { }
operator()
的参数中。 ,然后 lambda 将获得对该参数的引用。总成本:1 份。 operator()
的参数。 ,它将对该参数的引用传递给 lambda。总费用:无。 operator()
的参数中。 ,它将对该参数的引用传递给 lambda。总成本:1 次移动。 std::function<void(VeryBigType const&)> f = [](VeryBigType i) { }
operator()
将收到对它的引用。如果你用纯右值调用它,它将被物化为一个临时的,并且 operator()
将收到对此的引用。无论如何,对 lambda 的内部调用将始终复制。总成本:1 份。 std::function<void(VeryBigType const&)> f = [](VeryBigType const &i) { }
operator()
将只收到对它的引用,而 lambda 将只收到相同的引用。总费用:无。 那么,我们学到了什么?如果两者都
std::function
并且 lambda 引用,您可以避免任何无关的拷贝和移动。尽可能使用它。将按值 lambda 放入 by- const
-左值引用std::function
,但是,这是一个坏主意(除非您必须这样做)。本质上,左值引用“忘记”了参数的值类别,并且始终复制到 lambda 的参数。放一个by- const
-lvalue-reference lambda 内的按值 std::function
在性能方面非常好,但只有在调用其他需要按值的代码时才需要这样做 std::function
, 因为否则是一个引用 std::function
达到同样的目的,但复制和移动更少。将按值 lambda 放入按值 std::function
比放一个by-const
稍差-lvalue-reference lambda 在其中,由于所有调用中的额外移动。最好是通过右值引用来获取 lambda 的参数,这与通过 - const
获取它几乎相同。 -lvalue-reference 除非您仍然可以改变参数,就像您无论如何都按值获取它一样。TL;DR:
std::function
中的按值和右值引用参数模板参数应该对应于 by-rvalue-reference 或 by- const
-lvalue-reference 参数在您放入 std::function
的 lambda 中.类型中的左值引用参数应该对应于 lambda 中的左值引用参数。其他任何东西都会导致额外的拷贝或移动,并且应该只在需要时使用。
关于c++ - std::function - 值与引用参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61662210/