【问题标题】:Returning a lambda capturing a local variable返回捕获局部变量的 lambda
【发布时间】:2017-05-17 01:52:21
【问题描述】:

今天我在 C++11 lambdas 中遇到了一个非常不直观的行为(至少对我而言)。有问题的代码如下:

#include <stdio.h>

auto sum(int x) {
    return [&x](int y) {
        return x + y;
    };
}

int main() {
    int a = sum(2)(3);
    printf("%d\n",a);
}

这不是打印 5,而是打印乱码。实际上,至少在我的 GCC 版本中,如果我打开 -O2 优化标志,它实际上会打印 5。由于输出取决于编译器的优化级别,因此它是未定义的行为。过了一会儿,我想我明白发生了什么。

当函数 sum 被调用时,对应于参数 x 的堆栈变量被设置为 2,然后函数 sum 返回,并且这个堆栈变量可能被编译器需要放在那里的任何东西覆盖以执行以下代码,当 lambda 最终被执行时,x 所在的位置不再是 2,程序将 3 添加到任意整数。

有没有什么优雅的方式在 C++ 中进行柯里化以保证变量被正确捕获?

【问题讨论】:

  • 按值捕获[=]
  • 谢谢!这比我预期的要简单得多。
  • 仅供读者参考,这是 C++14,而不是 C++11。 C++14增加了函数返回值的类型推导。
  • 我用 g++ -std=c++11 编译,从 --version 的输出来看似乎是 2013 年的。也许这是 GCC 对 C++11 的非标准扩展?
  • 我认为这是对 GCC 的扩展,不应使用严格的编译器标志来允许

标签: c++ c++11 lambda currying


【解决方案1】:

int x 的生命周期有限。对自动存储变量(您称之为“堆栈”)的引用仅在变量的生命周期内有效。在这种情况下,只有到变量所在的堆栈帧(作用域)结束,或者函数参数的函数。

[&amp;] 通过引用捕获任何提到的(“本地”)变量,this 除外(如果使用或隐式使用,则按值捕获)。 [=] 按值捕获任何提到的变量。 [x] 将显式捕获x,并通过显式引用捕获[&amp;x]。在 C++17 中,[*this] 也可以使用。

还有[x=std::move(x)],或者[blah=expression]

一般来说,如果 lambda 的寿命超过当前范围,请不要使用 [&amp;]:明确说明您捕获的内容。

【讨论】:

  • 感谢您的详尽回答。我查找的大多数涉及 C++ 柯里化的答案都有很多我无法理解的模板代码,所以我才开始尝试一些东西。现在我更清楚自己在做什么了。
猜你喜欢
  • 2020-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 2020-02-13
  • 2017-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多