std::remove not working correctly, still has extra elements
std::vector<int> v = {1,2,3,4,5};
auto i = std::remove(v.begin(),v.end(),3);
for(auto j = v.begin(); j!= v.end();++j)
std::cout << *j;
Actual output : 12455
Where does extra 5 come 开发者_StackOverflow中文版from?
Desired output : 1245
How to achieve this?
remove
doesnt actually remove the elements
Remove removes from the range
[first, last)
all elements that are equal tovalue
. That is, remove returns an iteratornew_last
such that the range[first, new_last)
contains no elements equal tovalue
. 1 The iterators in the range[new_last, last)
are all still dereferenceable, but the elements that they point to are unspecified. Remove is stable, meaning that the relative order of elements that are not equal to value is unchanged.`
std::remove
algorithm works only using a pair of forward iterators and in general knows nothing about the underlying container.
You need to use the erase-remove
idiom to actually remove the element i.e combine erase
with remove
auto i = std::remove(v.begin(),v.end(),3);
v.erase(i,v.end());
for(auto j = v.begin(); j!= v.end();++j)
std::cout << *j;
Read the documentation for std::remove
again.
The function does not remove elements from a container (in fact, it doesn't even know that a container is involved, as it only sees iterators), it merely moves values in a sequence and return a new iterator i
such that all the interval [ begin .. i [
contains all non-removed elements in the original order. Elements left over in [ i .. end [
are unspecified, and it is your responsibility to eliminate that interval from a container (if you need it):
auto i = std::remove(...);
v.erase(i,v.end());
The reason why you have an additional 5
is that the typical removal algorithm copies values into holes left by removed values, and since values past the i
iterator are never overwritten, they remain the same as in the original sequence. This behavior, however, is not reliable - just eliminate the values past i
without reading them.
remove
returns the new end. So the fix of your code is this:
std::vector<int> v = {1,2,3,4,5};
auto newEnd = std::remove(v.begin(),v.end(),3);//return value stored in newEnd
for(auto j = v.begin(); j!= newEnd ;++j) //note j!=newEnd
std::cout << *j;
Output:
1245
Check it out yourself : http://www.ideone.com/3AMD9
Actually, std::remove
moves at beginning of the range all elements which don't satisfy predicate, AND returns iterator of the new end.
So usage is erase-remove idiom:
v.erase(std::remove(v.begin(), v.end(), 3), v.end());
In c++20, it can be simplified thanks to std::erase
:
std::erase(v, 3);
It's seams that you are printing the n+1 position of the vector in the for()
statement.
It should be:
for(auto j = v.begin(); j!= v.end();j++)
std::cout << *j;
j++
no ++j
精彩评论