Search code examples
c++vectoriteratorerase

Erase function of the std::vector


I have a std::vector and an iterator that points to an element in the vector. My question is how can I delete an element from the vector and keep the iterator?

I've tried using a second iterator to find the specific element that I want to delete and after erasing it with the erase function, the first iterator becomes invalid.


Solution

  • I have a std::vector and an iterator that points to an element in the vector. My question is how can I delete an element from the vector and keep the iterator?

    Please note that when an element is deleted, no iterator can point to it as it ceases to exist. So, to reference it's location normal practice is just use the returned iterator from the erase() method. This allows use of the insert() method which will put a value in the position of the previously erased object. With one iterator, just use this:

    auto loc_after = v.erase(iter);  // since the element has been erased loc_after points to the position the erased element had
    

    I've tried using a second iterator to find the specific element that I want to delete and after erasing it with the erase function, the first iterator becomes invalid.

    In the case of two iterators the elements can be easily erased by erasing the physically last iterator first since the earlier iterator is not invalidated. This is encapsulated in a function. The returned iterator points to one past the position of the "first" iterator regardless of order between the first and second iterator.

    #include <vector>
    #include <iostream>
    
    // This returns an iterator positioned after where  first_iter was before being erased
    // this allows the insert(pos, val) method to insert a value in the the location just prior to pos
    std::vector<int>::iterator second_iterator_loc(std::vector<int>& v, std::vector<int>::iterator first_iter, std::vector<int>::iterator second_iter)
    {
        std::vector<int>::iterator iter;
        if (first_iter < second_iter)
        {
            v.erase(second_iter);
            iter = v.erase(first_iter);
        }
        else if (second_iter < first_iter)
        {
            auto dist = first_iter - second_iter;
            v.erase(first_iter);
            iter = v.erase(second_iter) + dist - 1;
        }
        else
        {
            ;// handler in case both iterators point to the same object
        }
        return iter;
    }
    
    int main()
    {
        std::vector<int> v{ 1,2,3,4,5 };
        std::vector<int> v2 = v;
    
        std::vector<int>::iterator iter1 = v.begin() + 1; // points to 2 in v
        std::vector<int>::iterator iter2 = v.begin() + 3; // points to 4 in v
    
        std::vector<int>::iterator iter;
        iter = second_iterator_loc(v, iter1, iter2);
        v.insert(iter, 9);  // inserts a 9 in the previous location of the "first" iterator (where "2" was)
        for (auto x : v)
            std::cout << x << '\n'; // prints: 1 9 4 5
    
        v = v2;
        iter1 = v.begin() + 3; // reverse iterator positions
        iter2 = v.begin() + 1;
    
        iter = second_iterator_loc(v, iter1, iter2);
        v.insert(iter, 9);  // inserts a 9 in the previous location of the "first" iterator (where "4" was)
        for (auto x : v)
            std::cout << x << '\n'; // prints: 1 3 9 5
    
    }