Anon 123
Anon 123

Reputation: 83

C++ Vectors insertion and iterators confusion

int main(){
    vector<int> veclist;
    veclist.push_back(90);
    veclist.push_back(80);
    veclist.push_back(70);

    vector<int>::iterator it;
    it=veclist.begin();
    veclist.insert(it,20);
    cout << *it << endl;  // prints 20 
    it++;
    veclist.insert(it,99);
    cout << *it <<endl;  // line abc : prints 0 
}

Hi, I am working with vectors and iterators in C++. In the above code, why is "line abc" printing 0. Shouldn't it be printing 99 instead? When I print all the vector elements using a for loop, 99 is also printed but why isn't line abc doing so? I am dereferencing the iterator *it, and I expected it to hold the element 99.

Upvotes: 2

Views: 988

Answers (2)

songyuanyao
songyuanyao

Reputation: 172924

Because std::vector<T,Allocator>::insert causes iterator invalidation.

Causes reallocation if the new size() is greater than the old capacity(). If the new size() is greater than capacity(), all iterators and references are invalidated. Otherwise, only the iterators and references before the insertion point remain valid. The past-the-end iterator is also invalidated.

That means after insert's invocation, it has been invalidated. Usage of it like *it or it++ leads to UB.

You should assign it to the return value of insert, which is the iterator pointing to the inserted value. e.g.

vector<int>::iterator it;
it=veclist.begin();
it=veclist.insert(it,20);
cout << *it << endl;  // prints 20 
it++;
it=veclist.insert(it,99);
cout << *it <<endl;   // prints 99

Upvotes: 1

Kostas
Kostas

Reputation: 4176

When inserting in a vector, all previous iterators are invalidated. Everything after veclist.insert(it,20) is undefined behavior.

To be more precise about what happens under the hood the reason the first print works and the second doesn't is because of the allocated std::vector capacity. Most implementations allocate only 2^N memory chunks.

Therefore, initial vector has capacity of 4. When you increase size from 3 to 4, all previous iterators happen to remain valid. However, when size grows from 4 to 8, memory is copied in a new region, therefore you're accessing deleted memory.

To solve this, you can simply use the result of std::vector::insert, as the valid iterator pointing to the inserted element:

e.g.

it = veclist.insert(it,20);

Upvotes: 1

Related Questions