Reputation: 1214
I'm learning lambdas and am trying various examples, and I'm not sure I see why this doesn't work:
std::list<int> listIntegers;
listIntegers.push_back(40);
listIntegers.erase([listIntegers]() {
return std::find(listIntegers.begin(), listIntegers.end(), 40);
});
I also tried to write explicitely:
listIntegers.erase([listIntegers]()->std::list<int>::const_iterator {
return std::find(listIntegers.begin(), listIntegers.end(), 40);
});
However this of course works:
auto found40Iterator = std::find(listIntegers.begin(), listIntegers.end(), 40)
listIntegers.erase(found40Iterator);
Upvotes: 1
Views: 60
Reputation: 29022
Consider the case of
listIntegers.erase([listIntegers]()->std::list<int>::const_iterator {
return std::find(listIntegers.begin(), listIntegers.end(), 40);
});
The capture list [listIntegers]
is taking listInteger
by value, a copy is stored with the lambda. Since the listIntegers
used in std::find(listIntegers.begin(), listIntegers.end(), 40)
is a copy of the original, it will find element 40
within that copy. The returned iterator is therefore an iterator to the element in the copy and not in the original. Iterators can only be used with other iterators from the same container and with their original container. The problem you are seeing is that your lambda's return value is being used with listIntegers
but it actually refers to an element in a different range (the copy of listIntegers
).
The solution is to change your capture list to take listIntegers
by reference, so that it will operate on the original listIntegers
. There is also the problem that you are not calling the lambda, you are instead passing it as an argument to erase
. By adding a pair of parentheses we can instead call the lambda to and pass it's return value to erase
.
listIntegers.erase([&listIntegers]() {
// Added & here ^
return std::find(listIntegers.begin(), listIntegers.end(), 40);
}());
//^ Call the lambda
Upvotes: 2