我正在遍历带有auto(附加代码)的向量。在遍历时,我还在后面添加了一些元素。我没想到我得到的输出。
#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;
}
输出:
1
2
3
我期待从1到5的所有数字都会被打印出来。我无法理解如何遍历汽车?
答案 0 :(得分:5)
6.5.4 $ 1基于范围的声明[stmt.ranged]:
在每种情况下,基于范围的for语句等同于
{ auto && __range = range-init; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }
注意等效的伪代码__end
(和__begin
)将仅在循环开始时设置一次。在您的情况下,在循环的最后一次push_back之后,迭代器可能无效。如果是,则对它们的增量和比较将取决于实现。这意味着,作为其中一种可能性,__end
和__begin
将保持不变,并且循环计数不会发生变化。
答案 1 :(得分:5)
除了songyuanyao的答案所指出的问题,你提出的代码是未定义的行为。首先,由于push_back
,向量需要重新分配,然后所有迭代器都无效,因此增加循环变量是未定义的行为。
查看the documentation for push_back:
如果新的size()大于capacity()那么所有的迭代器和 引用(包括过去的结束迭代器)无效。 否则只有过去的迭代器无效。
,我想说在任何情况下,在基于范围的for语句中追加向量是未定义的行为,因为结束迭代器总是无效的。基于范围的存储初始end()
- 迭代器的副本,并且此迭代器在第一个push_back
之后失效。这与您的输出匹配,因为它仍然指向三元素向量的原始末尾。但是,您不应该依赖此行为。
遗憾的是,我无法在标准中找到“无效迭代器”语义的严格定义。 §24.2.1.11表示无效迭代器可能是单数,但只有解除引用它们的状态可能是未定义的行为。没有用于比较它们的语义,但考虑到向量的一个实现是使用内部存储之后的下一个内存地址,并且该地址在向量重新分配时更改,我会说循环是未定义的行为。