c ++ 11 лямбда-захват по значению, выдающая неправильное значение

Я пытаюсь сохранить лямбду в объектной системе, включающей несколько уровней косвенности. Я использую 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, несмотря на то, что оба ссылаются на один и тот же объект. Разница лишь в добавлении еще одного слоя косвенности.)

1

Решение

Это не верно:

auto temps = StoreSaved(
/* This temporary value dies at the last semicolon! */
SaveLambda([ten](){cout << "&ten: "<< &ten << endl; return ten;})
);

StoreSaved затем имеет указатель на несуществующий объект. Используя это UB.

4

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

Как уже указывалось другими, проблема заключается в том, что в 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(), так как вы больше не имеете дело с указателем.

1