Reputation: 45
I am practicing leetcode easy problem. I want to remove_if from an vector using lambda (for the first time, It is great). I get a negative pointer for new_end.
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional> // std::greater
using namespace std;
int main()
{
vector<int> a = { 2, 7, 11, 15 };
int target = 9;
auto new_end = std::remove_if(a.begin(), a.end(), [&a, target](const int x)
{
return std::count(a.begin(), a.end(), x) > target;
});
a.erase(new_end, a.end());
return 0;
}
There is no error but new_end is a negative pointer value.
Upvotes: 4
Views: 2370
Reputation: 40090
std::remove_if(begin, end, pred)
returns an iterator pointing at the first element to erase or end
if there is no element matching pred
. The later is true in your case:
auto new_end = std::remove_if(a.begin(), a.end(),
[&a, target](const int x) { return std::count(a.begin(), a.end(), x) > target; }
);
new_end
equals a.end()
. This value is printed as garbage by your debugger. But it happens to just works by chance in your case.
As pointed out by multiple commentators, once your predicate has returned true
once, the range [a.begin()
, a.end
) is modified and the last element has an unspecified value1.
This makes std::count(a.begin(), a.end(), x)
return unspecified values.
A suggested fix is to make a copy of a
before remove_if
starts to move things around. This is done by capturing it by value:
auto new_end = std::remove_if(a.begin(), a.end(),
[b=a, target](const int x) { return std::count(b.begin(), b.end(), x) > target; }
);
Initializing the copy to a new name b
simply emphasizes that it is a copy.
1) From std::remove_if
:
Iterators pointing to an element between the new logical end and the physical end of the range are still dereferenceable, but the elements themselves have unspecified values (as per MoveAssignable post-condition).
Upvotes: 2
Reputation: 7804
I assume to want to remove numbers greater than 9 from vector, Here is the code
vector<int> a = { 2, 7, 11, 15 };
int target = 9;
auto new_end = std::remove_if(a.begin(), a.end(), [](const int x)
{
return x > 9;
});
a.erase(new_end, a.end());
return 0;
The lambda argument 'x' will be provided by remove_if
, you don't need to add anything in the capture list
Upvotes: -1