简体   繁体   中英

Remove by iterator from std::vector

For removing an iterator from std::vector I can do these two things:

std::vector<int>& vec = myNumbers; // use shorter name
vec.erase(std::remove(vec.begin(), vec.end(), number_in), vec.end());

Or I can do this:

auto it = find(vec.begin(), vec.end(), number_in);
vec.erase(it);

The second is more intuitive, I guess, but which one is faster?

EDIT: Elements in vector are unique and we don't have to worry to delete several elements at once.

The first one is guaranteed to work correctly, while your second version may be faster (due to std::find stopping at the first item that matches), but it certainly is not safer.

auto it = find(vec.begin(), vec.end(), number_in);
if (it != vec.end())
   vec.erase(it);

That would ensure you are not erasing an invalid iterator.

So it depends on your needs. If you want a program that is correct, the first one works without further intervention, however the second requires a bug ticket from your customer and then you have to go fix it (as above).

The second is faster - the first will try to find all of elements which are equal to number_in , although it has already found one. However, the second will stop when it find one.

std::vector::erase

  • Removes the element at pos.

  • Removes the elements in the range [first; last).

    Invalidates iterators and references at or after the point of the erase, including the end() iterator. The iterator pos must be valid and dereferenceable. Thus the end() iterator (which is valid, but is not dereferencable) cannot be used as a value for pos. The iterator first does not need to be dereferenceable if first==last: erasing an empty range is a no-op.

http://en.cppreference.com/w/cpp/container/vector/erase

The first approach would be slower since the entire vector will be searched for the number. But it is also the safer way. Consider number_in is not an element of your vector. The first approach would try to erase an empty range which is defined and safe. And the second approach would try to erase the end iterator of your vector which is unsafe and UB.

It appears that you're interested in performance . Finding the (first) matching element cannot be done faster than O(n) . So, the part where you can try to improve performance is the removal, which can be O(1) , if you allow the order of the vector elements to change. For example

// find requires up to O(n)
auto it = std::find(v.begin(),v.end(),value);
// remove in O(1) but don't preserve order
if(it!=v.end()) {
  std::iter_swap(it,--(v.end()));
  v.pop_back();
}

Note that solutions using std::remove() and/or vector::erase() will preserve the order of the remaining elements and hence inevitable still compact the remaining elements (quoted from comment by Tony D), which is almost always more expensive than finding the matching element and hence dominates the computational costs.

Just try which solution is faster – the proof of the pudding is in the eating!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM