Я нахожу использование замыкания C++0x озадачивающим. Мой первоначальный отчет < /a> и последующий вызвали больше путаницы, чем объяснения. Ниже я покажу вам неприятные примеры и надеюсь выяснить, почему в коде возникает неопределенное поведение. Все фрагменты кода проходят компилятор 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, неопределенное поведение
#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::function нарушает код? почему программы №1-3 работают хорошо, а программа №4 корректна при трехкратном(!) вызове ac(1)? Почему программа № 4 застревает в следующих трех случаях, как если бы переменная x была захвачена по значению, а не по ссылке. И последние три вызова ac(1) совершенно непредсказуемы, как если бы любая ссылка на x была потеряна.