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

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

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

【问题讨论】:

  • 唯一的判断方法是分析一个优化的构建,看看是否存在性能差异。优化器非常聪明。

标签: c++ c++11 lambda c++14


【解决方案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 { /* ... */ }
} lambdaFunction2{someClassObj};

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 1970-01-01
    • 2021-02-03
    • 2017-08-02
    相关资源
    最近更新 更多