Lambda 捕获与参数 - 任何性能差异?

Posted

技术标签:

【中文标题】Lambda 捕获与参数 - 任何性能差异?【英文标题】:Lambda captures vs parameters - any performance difference? 【发布时间】:2021-11-19 04:06:27 【问题描述】:
auto lambdaFunction1 = [](someClass& obj, int x)/**/;
auto lambdaFunction2 = [&someClassObj, x]()/**/;

使用捕获变量或将它们作为参数传递的 lambda 是否会有任何性能差异?如果我处于可以使用任何东西的位置,我是否应该总是更喜欢其中一个选项而不是其他选项?有什么规则吗?还是只是喜欢谁的问题?

PS:我知道在同样的情况下我将没有这样的选择,例如使用 stl 算法,我问的是我可以同时使用这两种算法的情况

【问题讨论】:

唯一的判断方法是分析一个优化的构建,看看是否存在性能差异。优化器非常聪明。 【参考方案1】:

粗略的回答:

您是否在某个时候将 lambda 转换为对象(如 std::function)?

如果不是,并且每个 lambda 使用都是通过模板,很可能它都是内联的,这并不重要。大多数采用 lambda 参数的 STL 都是这样工作的,而且速度非常快。在这种情况下,请使用将来更容易阅读和理解的内容。

如果您确实将其转换为函数对象,那么使用常规函数指针而不是 std::function 会更便宜,因为函数本身没有动态分配的捕获对象。

更准确的答案:基准测试!

【讨论】:

为了清楚起见,您不能使用带有捕获 lambda 的常规函数​​指针 @PaulSanders 没错。函数点只是指向某段代码的指针。 std::function 有两个指针:一个指向代码的指针,以及一个类型擦除指针,指向保存捕获变量的内部结构。当然,具体实施可能会有所不同。【参考方案2】:

捕获和参数本质上是不同的,优化方式也不同。

让我们看看你的 lambdas:

struct lambdaFunction1_type 
    auto operator()(someClass& obj, int x) const  /* ... */ 
 lambrdaFunction1;

struct lambdaFunction2_type 
    someClass& obj;

    auto operator()(int x) const  /* ... */ 
 lambdaFunction2someClassObj;

如您所见,捕获的行为类似于类数据成员,而参数的行为类似于……嗯,一个参数。两者都有不同的用途。

两者还使用不同的内联过程。与往常一样,当使用诸如std::function 之类的多态包装器时,编译器优化的效果要差得多。如果没有堆省略,编译器可能不会优化动态分配的大小,因此它可能会影响优化的可能性。

如果我处于可以使用任何东西的位置,我是否应该总是更喜欢其中一个选项而不是其他选项?有什么规定吗?

我想说总是选择对你来说最清楚的东西。如果您对性能、度量、基准和配置文件有疑虑。

你也可以去检查一些代码生成的程序集。

【讨论】:

以上是关于Lambda 捕获与参数 - 任何性能差异?的主要内容,如果未能解决你的问题,请参考以下文章

如何在标准函数 lambda c++ 11 中正确捕获参数包

VS2010 中的 C++ 嵌套 lambda 错误,带有 lambda 参数捕获?

如何使用lambda表达式捕获局部变量?

将 lambda 中捕获的 const 值用作模板参数是不是合法?

C++20:非类型模板参数中的非捕获 lambda

可以在 C++11 lambda 中隐式捕获参数包吗?