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?
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.
This is called Range-based for loop.
6.5.4$1 The range-based for statement [stmt.ranged]:
In each case, a range-based for statement is equivalent to
{ auto && __range = range-init; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }
Note the equivalent pseudocode, __end (and __begin) will be set only once at the start of the loop. In your case, after the push_back at the last time of loop, the iterators might be invalid. If yes, the increment and comparsion on them will be implementation dependent. That means, as one of the possibilities, __end and __begin will remain the same, and loop count won't change.
来源:https://stackoverflow.com/questions/31310175/unusual-behavior-with-auto-while-traversing-a-dynamic-vector