Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unusual behavior with auto while traversing a dynamic vector

I am traversing a vector with auto ( code attached ). While traversing, I am also appending some elements at the back. I was not expecting the output that I got.

#include <iostream>
#include <vector>
using namespace std;

vector <int> dynamic_vector;

void access( )
{
    for ( auto i : dynamic_vector ) {
        if ( i == 3 ) {
            dynamic_vector.push_back( 4 );
            dynamic_vector.push_back( 5 );
        }
        cout << i << endl;
    }
}

int main() {
    dynamic_vector.push_back( 1 );
    dynamic_vector.push_back( 2 );
    dynamic_vector.push_back( 3 );
    access( );
    return 0;
}

Output:

1
2
3

I was expecting all numbers from 1 to 5 will get printed. I am not able to understand how traversing with auto works?

like image 581
ashwin1907 Avatar asked Jul 09 '15 06:07

ashwin1907


1 Answers

In addition to the problem pointed out by songyuanyao's answer, the code you present is undefined behavior. First, it is possible that the vector needs to reallocate because of a push_back, and then all iterator are invalidated and thus incrementing the loop variable is undefined behavior.

Looking at the documentation for push_back:

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.

, I would say that appending to the vector in a range-based for statement is undefined behavior in any case, because the end iterator is always invalidated. The range-based for stores a copy of the initial end()-iterator, and this iterator is invalidated after the first push_back. This matches to your output, because it still points to the original end of the three-element vector. However, you should not rely on this behavior.

Unfortuantely, I could not find a rigid definition of "invalid iterator" semantics in the standard. §24.2.1.11 says that invalid iterators may be singular, but only states that dereferencing them may be undefined behavior. There is no semantics for comparing them, but given the fact that one implementation for vectors is to use the next memory address following the internal storage, and that address changes when the vector reallocates, I would say that the loop is undefined behavior.

like image 60
Jens Avatar answered Sep 30 '22 17:09

Jens