STL中的矢量push_back

vector push_back in STL?

本文关键字:push back STL      更新时间:2023-10-16

我找到了一个用于STL矢量的示例程序

#include <vector>
#include <iostream>
using namespace std;
/* This one may well work with some compilers/OS, and crash with
   others. Who said the STL was safe ?? */
int main() {
  vector<int> v;
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);
  v.push_back(4);
  for (vector<int>::iterator i = v.begin();
       i != v.end(); i++) {
    cout << *i << endl;
    if (*i == 1) {
      v.push_back(5);
    }
  }
}

我期待着结果:1 2 3 4 5

但是,结果非常奇怪-1 0 3 4 0 33 0 0 0 0 00 0 0 0 49 0 1 2 3 4 5 5

我猜,这有一些逻辑,我遗漏了,因为这些看起来不像垃圾值,因为结果总是一样的。执行push_back后,迭代器是否被重置?我在某个地方读到,在迭代向量的同时附加到向量上不是一个好主意。我的问题是为什么?

经过一些互联网搜索,

     if (*i == 1) {
       size_t diff = i-v.begin();
       v.push_back(5);
       i = v.begin()+diff;
     }

这将解决问题。

您正在修改std::vector,同时对其进行循环。当调用std::vector::push_back()时,如果其当前size()等于其当前capacity(),则std::vector必须重新分配其内部数据存储以增加其容量,然后才能存储新值。这种重新分配将使循环iterator无效(end()迭代器总是无效的,但您在每次迭代中都会重新评估它,所以在这种情况下是可以的)。

要执行您正在尝试的操作,请执行以下任一操作:

  1. reserve()在进入循环之前vector的容量,以避免重新分配,从而避免使循环iterator无效。

  2. 每次重新分配后重置迭代器。

  3. 使用std::list,因为循环iterator不会被std::list::push_back()无效。

因为std::vector::push_back可能会使所有迭代器无效。

如果新的size()大于capacity(),则所有迭代器和引用(包括过去的结束迭代器)都将无效。

对于您的代码,可以使用std::vector::reserve来避免重新分配。

将容器的容量增加到大于或等于new_cap的值。

int main() {
  vector<int> v;
  v.reserve(5);  // ensure no reallocation until size() == 5
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);
  v.push_back(4);
  for (vector<int>::iterator i = v.begin();
       i != v.end(); i++) {
    cout << *i << endl;
    if (*i == 1) {
      v.push_back(5);
    }
  }
}

正如你所说,在迭代向量的同时附加到向量上不是一个好主意。

现有答案中有一些不错的选项,但值得一提的是,当您知道由于push_back大小超出容量而面临潜在的迭代器无效时,另一个经常被遗忘的选项是:

for (size_t i = 0; i < v.size(); ++i) {
    cout << v[i] << endl;
    if (v[i] == 1)
        v.push_back(5);
}

它是"C风格",但简单直观。