Я пытаюсь сохранить лямбду в объектной системе, включающей несколько уровней косвенности. Я использую g ++ 4.7.1.
В зависимости от того, как именно я создаю (эквивалентные) объекты, лямбда может иметь или не иметь правильное значение.
Код:
#include <iostream>
#include <functional> // used for std::function
using namespace std; // TODO nope
typedef function<int()> intf;struct SaveLambda {
const intf func;
SaveLambda(const intf& _func) : func(_func) {}
};struct StoreSaved {
const SaveLambda* child;
StoreSaved(const SaveLambda& _child) : child(&_child) {
cout << "Before returning parent: " << child->func() << endl;
}
};int main() {
const int ten = 10;
auto S = SaveLambda([ten](){return ten;});
cout << "No indirection: " << S.func() << endl << endl;
auto saved = StoreSaved(S);
cout << "Indirection, saved: " << saved.child->func() << endl << endl;
auto temps = StoreSaved ( SaveLambda([ten](){cout << "&ten: "<< &ten << endl; return ten;}) );
cout << "***** what. *****" << endl;
cout << "Indirection, unsaved: " << temps.child->func() << endl;
cout << "***** what. *****" << endl << endl;
cout << "ten still lives: " << ten << endl;
}
Компилировать как g++ -std=c++11 -Wall -o itest itest.cpp
и запустите: обратите внимание на одну строку вывода с другим значением.
Что я делаю неправильно? Я предположил, что захват по значению, ну, в общем, захват по значению. (Обратите внимание, что при печати в StoreSaved (строка 15) создается правильный значение, в отличие от строки 34, несмотря на то, что оба ссылаются на один и тот же объект. Разница лишь в добавлении еще одного слоя косвенности.)
Это не верно:
auto temps = StoreSaved(
/* This temporary value dies at the last semicolon! */
SaveLambda([ten](){cout << "&ten: "<< &ten << endl; return ten;})
);
StoreSaved
затем имеет указатель на несуществующий объект. Используя это UB.
Как уже указывалось другими, проблема заключается в том, что в temps
вы заканчиваете указателем на несуществующее SaveLambda
структура, так как она временная.
Вы можете сохранить копию, используя структуру SaveLambda в StoreSaved вместо указателя:
struct StoreSaved {
const SaveLambda child;
StoreSaved(const SaveLambda& _child) : child(_child) {
cout << "Before returning parent: " << child.func() << endl;
}
};
Вы также должны изменить все child->func()
в child.func()
, так как вы больше не имеете дело с указателем.