Unusual behavior with automatic when moving a dynamic vector

I move the vector from auto (code attached). When moving, I also add some elements to the back. I did not expect the results I received.

#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 expected all numbers from 1 to 5 to be printed. I can’t understand how it goes with auto-work?

+6
source share
2 answers

This is called the range for the cycle .

6.5.4 $ 1 Range-based for the [stmt.ranged] statement:

In each case, the range-based operator is equivalent

 { 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 beginning of the loop. In your case, after push_back at the last moment of the loop, the iterators may be invalid. If so, the increment and comparison on them will be implementation dependent. This means that as one of the possibilities, __end and __begin will remain unchanged, and the number of cycles will not change.

+5
source

In addition to the problem mentioned in the songyuanyao answer, the code you submitted is undefined. First, it is possible that the vector should be redistributed due to push_back , and then all iterators are invalid and thus increase the undefined loop variable.

See the documentation for push_back :

If the new size () is larger than the capacity (), then all iterators and links (including the past end iterator) are invalid. Otherwise, only the last end iterator is invalid.

I would say that adding to a vector in a range-based for statement is undefined behavior anyway, because the final iterator is always invalid. A range-based copy of the original end() -iterator is stored, and this iterator is invalid after the first push_back . This matches your result as it still points to the original end of the three element vector. However, you should not rely on this behavior.

Unfortunately, I could not find a hard definition of the semantics of the "invalid iterator" in the standard. Β§24.2.1.11 states that invalid iterators can be singular, but only the states that dereference them can be undefined. There is no semantics for comparing them, but taking into account the fact that one implementation for vectors is to use the next memory address following the internal memory, and this address changes when the vector is redistributed, I would say that the cycle is undefined.

+5
source

All Articles