0

When removing the given elements from the given array, I keep getting an error.

This is my code, I am not sure where I the error is:

int removeElement(vector<int>& nums, int val) {
        int i=0;
        int size=nums.size();
        if(size <=0){
            return 0;
        }
        for(int x : nums){
            if(x==val){
                nums.erase(nums.begin() + i );
            }
            i=i+1;   
        }
        int size1=nums.size();
        return size1;
    }

I then receive this error:

=================================================================
==33==ERROR: AddressSanitizer: negative-size-param: (size=-8)
    #8 0x7f3d479c882f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
0x603000000060 is located 0 bytes to the right of 32-byte region [0x603000000040,0x603000000060)
allocated by thread T0 here:
    #6 0x7f3d479c882f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
==33==ABORTING
Geno C
  • 1,401
  • 3
  • 11
  • 26
  • You can't remove elements from a vector while iterating over it. It will invalidate the current iterator and cause undefined behaviour. There's probably a duplicate ... somewhere. – Lukas-T Jul 28 '20 at 20:02
  • 1
    Does this answer your question? [How to delete an element from a vector while looping over it?](https://stackoverflow.com/questions/8597240/how-to-delete-an-element-from-a-vector-while-looping-over-it) – Lukas-T Jul 28 '20 at 20:07

1 Answers1

1

This loop:

for(int x : nums){

Is syntactic sugar that loops over the vector using iterators.

nums.erase(nums.begin() + i );

This invalidates the current iterator (and iterators to elements right of current element). Using the iterator such as for example incrementing it causes undefined behaviour.

The current iterator is incremented once the end of the loop body is reached. The behaviour of the program is undefined.


What you need to do is to use std::remove_if to move the remaining elements to the beginning of the vector, and then erase the elements at the end (that were moved from) using the overload that accepts a pair of iterators. This is called the erase-remove idiom.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • `std::remove_if` doesn't move elements to the end of the container. The data movement is good elements are moved to the left to overwrite "removed" elements. The elements after the new logical end have unspecified values. – Blastfurnace Jul 28 '20 at 20:17
  • @Blastfurnace True, technically. Regardless, the end state is the same from abstract point of view: Remaining elements are in the beginning, and elements to be erased are in the end. It's just that the removed elements aren't guaranteed to remain intact, which doesn't matter to the caller because they are about to be erased. – eerorika Jul 28 '20 at 20:27
  • I only mention it because there seems to be a common misconception that `std::remove` (and `std::remove_if`) act like a partition algorithm. A lot of people repeat that "removed elements are moved to the end" and they'll be surprised if they ever rely on that behavior. – Blastfurnace Jul 28 '20 at 20:32
  • @Blastfurnace Thanks for mentioning it. Although I "know" what `remove` does, the "wrong" algorithm is so much more intuitive that it springs into my mind when trying to explain it. – eerorika Jul 28 '20 at 20:35