316
vector<int> myVector;

and lets say the values in the vector are this (in this order):

5 9 2 8 0 7

If I wanted to erase the element that contains the value of "8", I think I would do this:

myVector.erase(myVector.begin()+4);

Because that would erase the 4th element. But is there any way to erase an element based off of the value "8"? Like:

myVector.eraseElementWhoseValueIs(8);

Or do I simply just need to iterate through all the vector elements and test their values?

Guy Avraham
  • 3,156
  • 3
  • 36
  • 46
Jake Wilson
  • 84,178
  • 88
  • 241
  • 352
  • 5
    @BenVoigt: your question is quite arrogant - clearly the guy cannot answer it, what YOU should have done is create an answer that covers all the cases you mention. – slashmais Nov 18 '16 at 04:45
  • 7
    @slashmais: Oh nonsense, my clarifying question was quite simple and doesn't require an expert programmer to answer. And there's no way I could cover all possible values of "what do you want to do?" for all three of the cases. Just for the case of "no matching elements" possible behaviors include "nothing", "throw an exception", "return an error", "exit the process (possibly via `assert()`)", "log a message to `std::cerr`"... and even those aren't exhaustive. No, the asker of the question needs to state the error handling policy, and whether finding no matches even is an error. – Ben Voigt Nov 18 '16 at 06:39
  • 3
    ... case of QED. i think – slashmais Nov 18 '16 at 08:49

4 Answers4

525

How about std::remove() instead:

#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 8), vec.end());

This combination is also known as the erase-remove idiom.

Community
  • 1
  • 1
Georg Fritzsche
  • 95,426
  • 26
  • 188
  • 233
  • 2
    I'm a bit confused... It appears this would erase elements from the vector from the element that I'm looking to erase, all the way to the end of the vector... Am I incorrect? All I want is that one element removed. – Jake Wilson Aug 02 '10 at 06:09
  • 13
    @jak: Take a look at the description of `remove()`: It moves all values not equal to the value passed to the beginning of the range `[begin,end)`. With your example in the question you'd get `5,9,2,0,7,7`. As `remove()` however returns an iterator to the new end, `vec.erase()` can remove the obsolete elements (i.e. the second `7` here) if that is needed. – Georg Fritzsche Aug 02 '10 at 06:28
  • 1
    Is it still necessary to call resize if erase() is used? (If so might consider including it in the answer?) – Assimilater Apr 05 '15 at 04:42
  • 3
    @Assimilater: It is not necessary. – Georg Fritzsche Apr 07 '15 at 12:45
  • 2
    what is the complexity of this procedure? O(n) ??? – shane Jun 23 '16 at 08:24
  • 2
    @shane The complexities of `erase()` and `remove()` are documented, see e.g. on [cppreference](http://en.cppreference.com/w/). – Georg Fritzsche Jun 23 '16 at 11:03
  • 16
    @GeorgFritzsche Why can't you just answer his question instead of sending him a link? Yes, it is O(n) –  Dec 09 '17 at 13:22
  • 3
    @AlisherKassymov Because the answer is easily found there. And it's a better approach for learning. Different people have different approaches, something worth respecting. – Georg Fritzsche Jan 04 '18 at 08:16
  • 5
    The dumb part of this algorithm is that remove doesn't stop when it finds the first match. It is inefficient to keep comparing the rest of the list. So this is great if there are potentially multiple copies of the same value in the vector, but it isn't a good answer for the common scenario of a vector of unique values. In that case, the std::find is a better option. – srm Jan 14 '20 at 19:22
  • Wouldn't it be great if there were `"erase_first"` and `"erase_all"` functions on vector? I know vector isn't intended for frequent removals - `list`, `deque` or possibly `set` should be used - but vector is memory efficient so a sensible choice in many situations even when there is some erasing. – Richard Whitehead Mar 06 '20 at 14:20
136

You can use std::find to get an iterator to a value:

#include <algorithm>
std::vector<int>::iterator position = std::find(myVector.begin(), myVector.end(), 8);
if (position != myVector.end()) // == myVector.end() means the element was not found
    myVector.erase(position);
Community
  • 1
  • 1
zneak
  • 130,082
  • 41
  • 248
  • 315
  • 18
    This is good if you only expect one occurence of that value. – Tomáš Zato - Reinstate Monica Nov 16 '15 at 08:46
  • 16
    @TomášZato: Or want only one removed, which seems to be the case for this question. – Gauthier Jun 02 '16 at 11:32
  • 3
    For removing all the values, initialize `position = myVector.begin()` and enclose everything in a `while(position != myVector.end())` loop – subtleseeker Jun 17 '18 at 16:17
  • `Error C2676 binary '==': 'action' does not define this operator or a conversion to a type acceptable to the predefined operator` in `xutility`. Literally any method I come across for this example gives me this error. – IOviSpot Oct 08 '20 at 18:05
  • Voted down because this is really not the way you should do this (the most upvoted answer is the correct way). – Carlo Wood Sep 13 '21 at 12:13
13

You can not do that directly. You need to use std::remove algorithm to move the element to be erased to the end of the vector and then use erase function. Something like: myVector.erase(std::remove(myVector.begin(), myVector.end(), 8), myVec.end());. See this erasing elements from vector for more details.

Community
  • 1
  • 1
Naveen
  • 71,879
  • 44
  • 171
  • 229
1

Eric Niebler is working on a range-proposal and some of the examples show how to remove certain elements. Removing 8. Does create a new vector.

#include <iostream>
#include <range/v3/all.hpp>

int main(int argc, char const *argv[])
{
    std::vector<int> vi{2,4,6,8,10};
    for (auto& i : vi) {
        std::cout << i << std::endl;
    }
    std::cout << "-----" << std::endl;
    std::vector<int> vim = vi | ranges::view::remove_if([](int i){return i == 8;});
    for (auto& i : vim) {
        std::cout << i << std::endl;
    }
    return 0;
}

outputs

2
4
6
8
10
-----
2
4
6
10

kometen
  • 5,148
  • 4
  • 40
  • 44