c ++ лямбда: функция суммы каррирования: возвращает разные результаты, используя захват по значению против ссылки - PullRequest
1 голос
/ 02 февраля 2020

У меня очень простая рекурсивная лямбда, которая вычисляет сумму заданных 2 чисел:

auto sum_v1 = [](auto first){
  return [first](auto second){
    return first + second;
  };
};

sum_v1 (1)(2); // returns 3, OK

Теперь та же самая функция, использующая захват по ссылке для аргумента сперва.

auto sum_v2 = [](auto first){
  return [&first](auto second){
    return first + second;
  };
};

sum_v2 (1)(2); // returns 4, NOT OK

sum_v2 получает аргумент first как 2, а аргумент second также 2.

Я знаю, как получить правильный результат. Я мог бы использовать либо sum_v1 ИЛИ sum_v3 (показано ниже).

// accept arg first using r-value reference
auto sum_v3 = [](auto&& first){
  return [first](auto second){
    return first + second;
  };
};

sum_v3 (1)(2); // returns 3, OK

Как sum_v2, создавая лямбду, видит arg first как 2. Я пытаюсь понять это.

Не могли бы вы дать мне несколько советов, чтобы лучше понять это? Я использую g cc .9.2.0 с -std = c ++ 17 на rhel 7.

Спасибо, Гаурав

1 Ответ

3 голосов
/ 02 февраля 2020

Это:

auto sum_v2 = [](auto first){
  return [&first](auto second){
    return first + second;
  };
};

Неопределенное поведение, так как вы берете ссылку на локальную переменную first, время жизни которой заканчивается до ее использования. Как и все UB, все может случиться. На вашей машине кажется, что first в итоге ссылается на second, но это не гарантировано. Код может взломать sh в других системах или привести к ожидаемому результату, но вы не можете на него полагаться.

С -Wall -Werror вы даже не сможете скомпилировать этот плохой код. Демо: https://godbolt.org/z/3gYx7q

...