0

A simple std::vector

std::vector<int> integers;
integers.push_back(10);
integers.push_back(11);    
cout  << "Before: " << integers.size();  //prints 2

I tried using 3 different versions of code to erase each element one by one C++5.1 and C++14

Version 1:

for( std::vector<int>::iterator it = integers.begin() ; it != integers.end() ; )
{
  cout << "\nVal: " << *it;
  it = integers.erase(it); 
}

cout << "\nAfter: " << integers.size(); 

Output: [Expected]

Before: 2
Val: 10
Val: 11
After: 0

Version 2 in C++14:

for( std::vector<int>::iterator it1, it = integers.begin() ; it != integers.end() ; )
{
    cout << "\nVal: " << *it;
    it1 = std::next(it);
    integers.erase(it);
    it = it1;
}

Output: [Unexpected]

Before: 2
Val: 10
After: 1

While for std::map, version 2 works as expected:

int main() {
    std::map<int, int> m;
    m.insert(make_pair(10, 11));
    m.insert(make_pair(12, 13));
    cout  << "Before: " << m.size();

    for( std::map<int, int>::iterator it1, it = m.begin() ; it != m.end() ; )
    {
        cout << "\nVal:  " << it->first << ", " << it->second;
        it1 = std::next(it);
        m.erase(it);
        it = it1;
    }
    cout << "\nAfter: " << m.size();
    return 0;
}

Outputs:

Before: 2
Val:  10, 11
Val:  12, 13
After: 0

Even this works :

for( std::map<int, int>::iterator it1, it = m.begin() ; it != m.end() ; )
{
    cout << "\nVal:  " << it->first << ", " << it->second;
    m.erase(it++);
}

Why version 2 works on std::map but not on std::vector?

Community
  • 1
  • 1
Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79
  • 1
    Where in the standard is it stated that `map<>::erase(it)` and `vector<>::erase(it)` have to exhibit the same behavior with the resulting iterator? The only thing I am aware of is that the first version is guaranteed to work in a generic way. – A.S.H Jan 03 '17 at 03:41
  • `map::erase` doesn't support version 1. Yes standard doesn't state that, but from developer's points of view, one can easily make mistake while using `version 2` with `vector`. – Saurav Sahu Jan 03 '17 at 03:46
  • I just tried it, with `it = m.erase(it);` and no use of `it1`, I get `After: 0` – A.S.H Jan 03 '17 at 03:54
  • 1
    You *could* click on [`erase`](http://www.cplusplus.com/reference/vector/vector/erase/) on the page you linked to and read about iterator invalidation. – molbdnilo Jan 03 '17 at 03:54

1 Answers1

1

The difference is that std::vector iterators are invalidated after erasing an element while for associative containers (23.2.4 Associative container)

9 The insert and emplace members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335