Я считаю использование замыкания C ++ 0x озадачивающим. Мой первоначальный отчет и последующий вызвали больше путаницы, чем объяснений. Ниже я покажу вам проблемные примеры, и я надеюсь выяснить, почему в коде есть неопределенное поведение. Все части кода проходят компилятор gcc 4.6.0 без предупреждения.
Программа № 1: Работает
#include <iostream>
int main(){
auto accumulator = [](int x) {
return [=](int y) -> int {
return x+y;
};
};
auto ac=accumulator(1);
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}
Результат соответствует ожиданиям:
2 2 2
2 2 2
2 2 2
2. Программа № 2: закрытие, отлично работает
#include <iostream>
int main(){
auto accumulator = [](int x) {
return [&](int y) -> int {
return x+=y;
};
};
auto ac=accumulator(1);
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}
Вывод:
4 3 2
7 6 5
10 9 8
Программа 3: Программа № 1 с std :: function, отлично работает
#include <iostream>
#include <functional> // std::function
int main(){
typedef std::function<int(int)> fint2int_type;
typedef std::function<fint2int_type(int)> parent_lambda_type;
parent_lambda_type accumulator = [](int x) -> fint2int_type{
return [=](int y) -> int {
return x+y;
};
};
fint2int_type ac=accumulator(1);
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}
Вывод:
2 2 2
2 2 2
2 2 2
Программа 4: Программа № 2 с std :: function, Undefined Behavior
#include <iostream>
#include <functional> // std::function
int main(){
typedef std::function<int(int)> fint2int_type;
typedef std::function<fint2int_type(int)> parent_lambda_type;
parent_lambda_type accumulator = [](int x) -> fint2int_type{
return [&](int y) -> int {
return x+=y;
};
};
fint2int_type ac=accumulator(1);
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}
Первый запуск программы дает:
4 3 2
4 3 2
12364812 12364811 12364810
Второй запуск той же программы:
4 3 2
4 3 2
1666060 1666059 1666058
Третий:
4 3 2
4 3 2
2182156 2182155 2182154
Как мое использование функции std :: нарушает код? почему программы № 1-3 работают хорошо, а программа № 4 корректна при вызове ac (1) трижды (!)? Почему Программа № 4 застревает в следующих трех случаях, как если бы переменная x была захвачена по значению, а не по ссылке. И последние три вызова ac (1) совершенно непредсказуемы, как если бы любая ссылка на x была бы потеряна.