带有意外结果的c ++闭包

时间:2018-06-06 03:08:16

标签: c++ lambda closures

我正在测试一些关于闭包的功能,但我遇到了一些问题,这里有一些代码,有3个lambda函数的向量,这些函数捕获BuildFns中的局部变量,我所有的内存位置是相同的,但是,只有主函数的第一次调用实际输出3,当我们在main中调用它们时,我们是否应该期望向量输出3中的所有函数?

#include <iostream>
#include <vector>
using namespace std;
auto BuildFns() {
  vector<function<void()>> vec;
  for (int i = 0; i < 3; i++) {
    cout << &i << '\n';
    vec.push_back([&i]() {
      cout << i << endl;
      cout << &i << '\n';
    });
  }
  return vec;
}


auto main() -> int {
  auto vec = BuildFns();
  vec[0]();
  vec[1]();
  vec[2]();
}

输出:

0x7ffeedfa25c8
0x7ffeedfa25c8
0x7ffeedfa25c8
3
0x7ffeedfa25c8
-1581316512  // what's wrong with this i? isn't it contained in the closure environment and can't be written if it's still been accessed?
0x7ffeedfa25c8
-1581316512
0x7ffeedfa25c8

预期:

0xaddress_of_i
0xaddress_of_i
0xaddress_of_i
3
0xaddress_of_i
3
0xaddress_of_i
3
0xaddress_of_i

1 个答案:

答案 0 :(得分:1)

这里的问题是你正在通过引用(&i)对超出范围(i)的本地变量进行捕获BuildFns()。通过引用捕获也可以是指针,并且作为局部变量,在这种情况下可能是指向堆栈的指针。因此,您不应对该值随机变化感到惊讶。所需要的只是std::function调用中的某些机制写入堆栈,然后你的价值就消失了。

如果您在创建闭包时确实需要i的值,请改为按值捕获。