开发者

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 to value. That is, remove returns an iterator new_last such that the range [first, new_last) contains no elements equal to value. 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜