在遍历动态矢量时使用auto的不寻常行为

ash*_*907 6 c++ iterator vector auto c++11

我正在遍历带有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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

1
2
3
Run Code Online (Sandbox Code Playgroud)

我期待从1到5的所有数字都会被打印出来.我无法理解如何遍历汽车工作?

son*_*yao 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
  }
}
Run Code Online (Sandbox Code Playgroud)

注意等效伪代码,__end(和__begin)将在循环开始时只设置一次.在您的情况下,在循环的最后一次push_back之后,迭代器可能无效.如果是,则对它们的增量和比较将取决于实现.这意味着,作为其中一种可能性,__end并且__begin将保持不变,并且循环计数不会改变.


Jen*_*ens 5

除了songyuanyao的答案所指出的问题,你提出的代码是未定义的行为.首先,有可能因为a push_back而需要重新分配向量,然后所有迭代器都无效,因此增加循环变量是未定义的行为.

看着为的push_back的文档:

如果new size()大于capacity(),那么所有迭代器和引用(包括过去的迭代器)都将失效.否则只有过去的结束迭代器无效.

,我会说在任何情况下,在基于范围的for语句中追加向量是未定义的行为,因为结束迭代器总是无效的.基于范围的存储初始end()-iterator 的副本,并且此迭代器在第一个之后无效push_back.这与您的输出匹配,因为它仍然指向三元素向量的原始末尾.但是,您不应该依赖此行为.

遗憾的是,我无法在标准中找到"无效迭代器"语义的严格定义.§24.2.1.11表示无效迭代器可能是单数,但只有解除引用它们的状态可能是未定义的行为.没有用于比较它们的语义,但考虑到向量的一个实现是使用内部存储之后的下一个内存地址,并且该地址在向量重新分配时更改,我会说循环是未定义的行为.