закрытие c ++ с неожиданным результатом - PullRequest
0 голосов
/ 06 июня 2018

Я тестирую некоторые функции, связанные с замыканиями, но я сталкиваюсь с некоторыми проблемами, вот некоторый код, есть вектор из 3 лямбда-функций, эти функции записывают локальную переменную внутри BuildFns, все места в памяти i одинаковы,но только первый вызов из функции main на самом деле выводит 3, следует ли нам ожидать, что все функции внутри векторного вывода 3 будут вызваны в main?

#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 голосов
/ 06 июня 2018

Проблема здесь в том, что вы выполняете захват по ссылке (&i) для локальной переменной, которая выходит из области видимости (i) в момент, когда возвращается BuildFns().Захват по ссылке также может быть указателем и, в качестве локальной переменной, скорее всего указателем на стек в этом случае.Таким образом, вы не должны удивляться, что значение случайно меняется.Все, что нужно для того, чтобы какой-то механизм в вызове std::function записал в стек, а затем ваше значение исчезло.

Если вы действительно хотите значение i во время созданиязакрытие, вместо этого сделайте захват по значению.

...