704

I have a std::vector<int>, and I want to delete the nth element. How do I do that?

Example:

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

vec.erase(???);
W D
  • 204
  • 1
  • 10
dau_man
  • 7,059
  • 3
  • 17
  • 5
  • 5
    Consider using a std::deque which provides inserting and deleting at both ends. – Dario May 17 '09 at 18:20
  • 74
    No, don't consider using deque just because you may want to delete an element, that's really poor advice. There's a whole load of reasons why you may want to use deque or vector. It is true that deleting an element from a vector can be costly - esp if the vector is large, but there's no reason to think that a deque would be any better than a vector from the code example you just posted. – Owl Apr 01 '17 at 21:10
  • 11
    For example, if you have a graphical application where you display a "list" of things where you insert/remove things interactively, consider you run through the list 50-100 times each second to display them, and you add/remove things a few times each minute. So implementing the "list" as a vector is probably a better option in term of total efficiency. – Michel Billaud May 28 '17 at 17:54
  • 1
    I recommend std::vector.erase(...), which is also my preference - you can choose to delete either a single element or a range. –  Oct 30 '20 at 15:13

16 Answers16

857

To delete a single element, you could do:

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

// Deletes the second element (vec[1])
vec.erase(std::next(vec.begin()));

Or, to delete more than one element at once:

// Deletes the second through third elements (vec[1], vec[2])
vec.erase(std::next(vec.begin(), 1), std::next(vec.begin(), 3));
Tobi
  • 2,591
  • 15
  • 34
mmmmmmmm
  • 15,269
  • 2
  • 30
  • 55
  • 72
    Note also binary `operator+` is __not__ necessarily defined for iterators on other container types, like `list::iterator` (you cannot do `list.begin() + 2` on an `std::list`, you have to use [`std::advance`](http://www.cplusplus.com/reference/iterator/advance/) for that) – bobobobo Mar 14 '13 at 23:35
  • are you stating that the "+1" is the first element myVector[0] or the actual position myVector[1] – basickarl Sep 19 '14 at 07:38
  • it+1 is element with id 1, e.g container[1]. first element is +0. See the comment below... – Nick Apr 12 '16 at 06:22
  • 3
    With advance you must save the iterator in a variable. If you use std::next you can do it in one line: vec.erase( next(begin(vec), 123) ); – dani Oct 05 '16 at 20:36
  • 33
    Thank you to all who have answered. What are we to think of a class design when such a simple operation as deleting an element, requires one to come to StackOverflow? – Pierre Jan 28 '18 at 18:35
  • what is `begin()`?, why not just `1`? – user25 Apr 10 '18 at 11:58
  • 1
    @user25 erase takes in a vector::iterator, not an int. begin() is the itterator at the start of the vector, or element [0]. By adding to it, we increment it by the number of elements required to find the element we want to remove. – Force Gaia Jun 11 '18 at 14:14
  • 8
    @Pierre because the *numerical index* of a particular element is not the primary model of access, *iterator* is. All the functions that look at elements of a container use that container's iterators. E.g. [`std::find_if`](https://en.cppreference.com/w/cpp/algorithm/find) – Caleth Jul 03 '18 at 09:38
  • 4
    @Caleth yeah, but std::vector could still provide a method for this very common use-case. Everybody bashes Qt containers, but QList for instance has removeOne() which is just a no-brainer compared to the ugliness of std::vector. – Richard W Jan 20 '21 at 21:19
  • @RichardW Let's not turn beautiful `std::vector` into nightmarish `std::string`. – Evg Jul 17 '21 at 06:33
  • 2
    @Caleth Huh? Access by index (`at()` and `operator[]`) is one of the main distinctive properties of `std::vector`. It would only be consistent to also support inserting and erasing at an index. – user686249 Dec 09 '22 at 10:48
440

The erase method on std::vector is overloaded, so it's probably clearer to call

vec.erase(vec.begin() + index);

when you only want to erase a single element.

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
CodeBuddy
  • 5,749
  • 1
  • 25
  • 30
  • 4
    But that problem appears no matter how many elements you have. – Zyx 2000 Sep 01 '14 at 09:32
  • 17
    if there's only one element, index is 0, and so you get `vec.begin()` which is valid. – Anne Quinn Jan 27 '15 at 18:28
  • 58
    I wish someone would have mentioned that `vec.erase(0)` does not work, but `vec.erase(vec.begin()+0)` (or without +0) does. Otherwise I get no matching function call, which is why I came here – droid192 Feb 15 '16 at 20:19
  • @qrtLs `vec.erase(0)` may actually compile if `0` happens to be interpreted as the null pointer constant ... – L. F. Jul 24 '19 at 09:51
  • 6
    @qrtLs erase() function takes iterator type as the argument; as 0 is not an iterator, it would give compiler error as no matching function call. – dixit_chandra May 24 '21 at 22:28
68
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
    std::vector<T>::iterator it = vec.begin();
    std::advance(it, pos);
    vec.erase(it);
}
Max
  • 1,037
  • 8
  • 9
  • 2
    Max, what makes that function better than: `template void remove(std::vector& vec, size_t pos) { vec.erase(vec.begin + pos); }` I'm not saying either is better, merely asking out of personal interest and to return the best result this question could get. –  Sep 11 '12 at 20:50
  • 15
    @JoeyvG: Since a `vector::iterator` is a random-access iterator, your version is fine and maybe a bit clearer. But the version that Max posted should work just fine if you change the container to another one that doesn't support random-access iterators – Lily Ballard Sep 11 '12 at 21:28
  • 3
    This is imo the better answer, as it applies to other container formats too. You could also use std::next(). – Bim Dec 23 '16 at 18:27
  • Much better approach since it doesn't rely on the internals of the container. – BartoszKP May 20 '20 at 10:13
  • std::advance is only needed if you think this will not be a vector i.e. a list. But as you've specified that here, would operator+ not be simpler ? According to this https://stackoverflow.com/questions/1668088/advance-iterator-for-the-stdvector-stdadvance-vs-operator there is a possible gain in performance with operator+ – Goblinhack Jun 08 '20 at 12:23
  • It should be `typename std::vector::iterator it = vec.begin();` or just `auto it = vec.begin();` – Jabberwocky Jan 14 '22 at 11:05
40

The erase method will be used in two ways:

  1. Erasing single element:

    vector.erase( vector.begin() + 3 ); // Deleting the fourth element
    
  2. Erasing range of elements:

    vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
    
aksh1618
  • 2,245
  • 18
  • 37
Eswaran Pandi
  • 602
  • 6
  • 10
  • 26
    This is a duplicate answer almost 7 years after the accepted answer. Please don't do this. – AlastairG Jun 26 '19 at 14:55
  • 7
    @AlastairG This answer is a lot shorter and clearer than the original answer, though it could technically simply be an edit instead (Such an edit might be against the wishes of the original answer's OP though) – Nicholas Pipitone Sep 27 '20 at 17:24
  • I think we should add - it removes from 4th to 6th element excluded (6th element is not included/erased) – Maciek Woźniak Dec 06 '21 at 02:35
36

Erase an element with index :

vec.erase(vec.begin() + index);

Erase an element with value:

vec.erase(find(vec.begin(),vec.end(),value));
Arya
  • 547
  • 5
  • 5
  • 2
    Please make more obvious the additional insight this answer provides in comparison to other existing older and upvoted answers. – Yunnosch Sep 07 '20 at 11:49
16

Actually, the erase function works for two profiles:

  • Removing a single element

    iterator erase (iterator position);
    
  • Removing a range of elements

    iterator erase (iterator first, iterator last);
    

Since std::vec.begin() marks the start of container and if we want to delete the ith element in our vector, we can use:

vec.erase(vec.begin() + index);

If you look closely, vec.begin() is just a pointer to the starting position of our vector and adding the value of i to it increments the pointer to the position i. So, we instead can access the pointer to the ith element with &vec[i]:

vec.erase(&vec[i]); // To delete the ith element
Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
Varun Garg
  • 565
  • 7
  • 12
14

If you have an unordered vector you can take advantage of the fact that it's unordered and use something I saw from Dan Higgins at CPPCON

template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
    if ( inIndex < inContainer.size() )
    {
        if ( inIndex != inContainer.size() - 1 )
            inContainer[inIndex] = inContainer.back();
        inContainer.pop_back();
        return true;
    }
    return false;
}

Since the list order doesn't matter, just take the last element in the list and copy it over the top of the item you want to remove, then pop and delete the last item.

Clay J
  • 149
  • 1
  • 2
  • I think this is the best answer if the vector is unordered. It does not rely on the assumption that `iterator + index` will actually give you back the iterator position at that index, which is not true of all iterable containers. It is also constant complexity instead of linear by taking advantage of the back pointer. – theferrit32 Mar 15 '18 at 18:57
  • 3
    This totally needs to be added to the std lib as ```unordered_remove``` and ```unordered_remove_if``` … unless it has been and I missed it, which is happening more and more often these days :) – Will Crawford Mar 12 '20 at 02:35
  • 2
    If would suggest to use move-assignment or swap instead of a copy-assignment. – Carsten S Mar 12 '20 at 10:44
  • `std::remove` reorders the container so that all the elements to be removed are at the end, no need to do it manually like this if you are using C++ 17. – keith Apr 20 '20 at 18:45
  • 1
    @keith how does `std::remove` help? cppreference claims that even in C++17, all `remove` overloads require a predicate, and none take an index. – Paul Du Bois May 26 '20 at 23:54
12

It may seem obvious to some people, but to elaborate on the above answers:

If you are doing removal of std::vector elements using erase in a loop over the whole vector, you should process your vector in reverse order, that is to say using

for (int i = v.size() - 1; i >= 0; i--)

instead of (the classical)

for (int i = 0; i < v.size(); i++)

The reason is that indices are affected by erase so if you remove the 4-th element, then the former 5-th element is now the new 4-th element, and it won't be processed by your loop if you're doing i++.

Below is a simple example illustrating this where I want to remove all the odds element of an int vector;

#include <iostream>
#include <vector>

using namespace std;

void printVector(const vector<int> &v)
{
    for (size_t i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;
}

int main()
{    
    vector<int> v1, v2;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
        v2.push_back(i);
    }

    // print v1
    cout << "v1: " << endl;
    printVector(v1);
    
    cout << endl;
    
    // print v2
    cout << "v2: " << endl;
    printVector(v2);
    
    // Erase all odd elements
    cout << "--- Erase odd elements ---" << endl;
    
    // loop with decreasing indices
    cout << "Process v2 with decreasing indices: " << endl;
    for (int i = v2.size() - 1; i >= 0; i--)
    {
        if (v2[i] % 2 != 0)
        {
            cout << "# ";
            v2.erase(v2.begin() + i);
        }
        else
        {
            cout << v2[i] << " ";
        }
    }
    cout << endl;
    cout << endl;
    
    // loop with increasing indices
    cout << "Process v1 with increasing indices: " << endl;
    for (int i = 0; i < v1.size(); i++)
    {
        if (v1[i] % 2 != 0)
        {
            cout << "# ";
            v1.erase(v1.begin() + i);
        }
        else
        {
            cout << v1[i] << " ";
        }
    }
    
    
    return 0;
}

Output:

v1:
0 1 2 3 4 5 6 7 8 9

v2:
0 1 2 3 4 5 6 7 8 9
--- Erase odd elements ---
Process v2 with decreasing indices:
# 8 # 6 # 4 # 2 # 0

Process v1 with increasing indices:
0 # # # # #

Note that on the second version with increasing indices, even numbers are not displayed as they are skipped because of i++

Note also that processing the vector in reverse order, you CAN'T use unsigned types for indices (for (uint8_t i = v.size() -1; ... won't work). This because when i equals 0, i-- will overflow and be equal to 255 for uint8_t for example (so the loop won't stop as i will still be >= 0, and probably out of bounds of the vector).

Pierre Baret
  • 1,773
  • 2
  • 17
  • 35
6

If you work with large vectors (size > 100,000) and want to delete lots of elements, I would recommend to do something like this:

int main(int argc, char** argv) {

    vector <int> vec;
    vector <int> vec2;

    for (int i = 0; i < 20000000; i++){
        vec.push_back(i);}

    for (int i = 0; i < vec.size(); i++)
    {
        if(vec.at(i) %3 != 0)
            vec2.push_back(i);
    }

    vec = vec2;
    cout << vec.size() << endl;
}

The code takes every number in vec that can't be divided by 3 and copies it to vec2. Afterwards it copies vec2 in vec. It is pretty fast. To process 20,000,000 elements this algorithm only takes 0.8 sec!

I did the same thing with the erase-method, and it takes lots and lots of time:

Erase-Version (10k elements)  : 0.04 sec
Erase-Version (100k elements) : 0.6  sec
Erase-Version (1000k elements): 56   sec
Erase-Version (10000k elements): ...still calculating (>30 min)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fabian
  • 119
  • 1
  • 4
5

I suggest you read about the erase–remove idiom.
For example:

vec.erase(vec.begin() + 1, vec.begin() + 3);

With this, you will erase the nth element of vec but before you erase the second element, all the other elements of vec will be shifted and the vector size will be reduced by 1. This can be a problem as you may be looping through vec while its size() is decreasing.

If you have problem like this the provided link suggests to use remove and remove_if.

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
explorer
  • 93
  • 1
  • 7
3

To delete an element use the following way:

// declaring and assigning array1 
std:vector<int> array1 {0,2,3,4};

// erasing the value in the array
array1.erase(array1.begin()+n);

For a more broad overview you can visit: http://www.cplusplus.com/reference/vector/vector/erase/

rayryeng
  • 102,964
  • 22
  • 184
  • 193
cammando
  • 596
  • 7
  • 20
  • Consider using [cppreference](https://en.cppreference.com/). See [this](https://stackoverflow.com/questions/6520052/whats-wrong-with-cplusplus-com), [this](https://meta.stackoverflow.com/questions/275760/should-we-complain-about-the-resources-linked-in-answers), etc. – L. F. Feb 07 '19 at 10:13
3

if you need to erase an element inside of a for-loop, do the following:

for(int i = 0; i < vec.size(); i++){

    if(condition)
        vec.erase(vec.begin() + i);

}
Disembleergon
  • 187
  • 4
  • 5
2

You need to use the Standard Template Library's std::vector::erase function.

Example: Deleting an element from a vector (using index)

// Deleting the eleventh element from vector vec
vec.erase( vec.begin() + 10 ); 

Explanation of the above code

std::vector<T,Allocator>::erase Usage:

iterator erase (iterator position); // until C++11
iterator erase( const_iterator pos ); // since C++11 and until C++20
constexpr iterator erase( const_iterator pos ); // since C++20

Here there is a single parameter, position which is an iterator pointing to a single element to be removed from the vector. Member types iterator and const_iterator are random access iterator types that point to elements.

How it works

erase function does the following:

  • It removes from the vector either a single element (position) or a range of elements ([first, last)).

  • It reduces the container size by the number of elements removed, which are destroyed.

Note: The iterator pos must be valid and dereferenceable. Thus the end() iterator (which is valid, but is not dereferenceable) cannot be used as a value for pos.

Return value and Complexity

The return value is an iterator pointing to the new location of the element that followed the last element that was erased by the function call. This is the container end of the operation that erased the last element in the sequence.

Member type iterator is a random access iterator type that points to elements.

Here, the time complexity is linear on the number of elements erased (destructions) plus the number of elements after the last element is deleted (moving).

samnoon
  • 1,340
  • 2
  • 13
  • 23
0

The previous answers assume that you always have a signed index. Sadly, std::vector uses size_type for indexing, and difference_type for iterator arithmetic, so they don't work together if you have "-Wconversion" and friends enabled. This is another way to answer the question, while being able to handle both signed and unsigned:

To remove:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
    v.erase(iter);
}

To take:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);

    auto val = *iter;
    v.erase(iter);

    return val;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rian Quinn
  • 1,766
  • 12
  • 22
0

here is one more way to do this if you want to delete a element by finding this with its value in vector,you just need to do this on vector.

vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));

it will remove your value from here. thanks

meenachinmay
  • 389
  • 2
  • 6
-5

the fastest way (for programming contests by time complexity() = constant)

can erase 100M item in 1 second;

    vector<int> it = (vector<int>::iterator) &vec[pos];
    vec.erase(it);

and most readable way : vec.erase(vec.begin() + pos);

R.hatam
  • 1
  • 1