Возврат лямбда-захвата локальной переменной

Сегодня я столкнулся с очень не интуитивным поведением (по крайней мере для меня) в лямбдах C ++ 11. Код, о котором идет речь, следующий:

#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 возвращается, и эта переменная стека может быть перезаписана всем, что нужно поместить компилятору для выполнения следующего кода, и время, когда лямбда в конечном итоге исполняется, место, где x больше не содержит 2, и программа добавляет 3 к произвольному целому числу.

Есть ли какой-нибудь элегантный способ сделать карри в C ++, гарантирующий, что переменная будет перехвачена правильно?

5

Решение

int x имеет ограниченный срок службы. Ссылки на переменные автоматического хранения (то, что вы называете «стеком») действительны только в течение времени жизни переменной. В этом случае только до конца стекового фрейма (области видимости), где существует переменная, или функции для аргументов функции.

[&] захватывает любую упомянутую («локальную») переменную по ссылке, кроме this (который фиксируется значением, если используется или используется неявно). [=] захватывает любую упомянутую переменную по значению. [x] будет захватывать x явно, и [&x] по ссылке явно. В C ++ 17 [*this] тоже работает.

Существует также [x=std::move(x)], или же [blah=expression],

В общем, если лямбда переживет текущую область, не используйте [&]: будьте откровенны о том, что вы захватываете.

8

Другие решения

Других решений пока нет …