Ovidiu Firescu
Ovidiu Firescu

Reputation: 405

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.

Upvotes: 0

Views: 165

Answers (3)

doug
doug

Reputation: 4289

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

}

Upvotes: 2

Ton van den Heuvel
Ton van den Heuvel

Reputation: 10528

std::vector::erase will invalidate all iterators at or after the erased element:

Invalidates iterators and references at or after the point of the erase, including the end() iterator.

However, erase will return an iterator pointing to the element following the last removed element. Maybe that is enough to satisfy your use case?

Upvotes: 2

eerorika
eerorika

Reputation: 238311

My question is how can I delete an element from the vector and keep the iterator?

You can't using std::vector::iterator. The iterator will be invalidated by erasing the element.

But you could achieve this by writing your own iterator class that stores a pointer to the vector and an index.

Upvotes: 2

Related Questions