/* DREAM OUTPUT:
INT: 1
TESTINT: 1
TESTINT: 2
TESTINT: 23
TESTINT: 24
TESTINT: 25
TESTINT: 3
TESTINT: 4
TESTINT: 5
TESTINT: 6
INT: 23
INT: 24
INT: 25
INT: 3
INT: 4
INT: 5
INT: 6
ERROR 1: Not erasing the '2' causes a bizzare effect.
ERROR 2: Erasing the '2' causes memory corruption.
#include <cstdlib>
#include <iostream>
#include <vector>
int main(int argc, char* argv[])
{
std::vector<int> someInts;
someInts.push_back(1);
someInts.push_back(2);
someInts.push_back(3);
someInts.push_back(4);
someInts.push_back(5);
someInts.push_back(6);
for(std::vector<int>::iterator currentInt = someInts.begin();
currentInt != someInts.end(); ++currentInt)
if(*currentInt == 2)
{
std::vector<int> someNewInts;
someNewInts.push_back(23);
someNewInts.push_back(24);
someNewInts.push_back(25);
someInts.insert(currentInt + 1, someNewInts.begin(), someNewInts.end());
//someInts.erase(currentInt);
for(std::vector<int>::iterator testInt = someInts.begin();
testInt != someInts.end(); ++testInt)
std::cout << "TESTINT: " << *testInt << '\n';
}
else
std::cout << "INT: " << *currentInt << '\n';
return 0;
}
代码非常明显,但我想知道这里发生了什么。这是一个复制品,使用了一个更大的项目中发生的事情。这令我感到困惑。
答案 0 :(得分:3)
将元素插入向量会导致与其关联的迭代器无效,因为向量可以增长,因此它会分配其内部存储空间。
答案 1 :(得分:3)
由于someInts.erase(currentInt);
使currentInt无效,因此在设置正确之前无法使用它。
恰好erase()
返回列表中的有效迭代器以继续。
一个迭代器,它指定除了删除的任何元素之外的第一个元素,或者如果不存在这样的元素则指向向量末尾的指针。
尝试
currentInt = someInts.erase(currentInt);
将外部循环置于'23'作为测试数据的开始,并在下一循环中逐步变为'24'。
答案 2 :(得分:2)
您需要了解stl集合之间的差异。
Vector是一个连续的(通常)内存块。当你插入中间时,它会尝试通过为现有数据和新数据重新分配足够的内存,然后将它们全部复制到正确的位置并让你继续,好像什么都没发生一样。然而,正如你所发现的那样 - 发生了一些事情。用于引用旧内存块的迭代器仍指向那里 - 但数据已被移动。如果您尝试使用它们,则会出现内存错误。
一个答案是确定迭代器用于指向的位置,并将其更新为指向新位置。通常,人们使用[]运算符,但你可以使用begin()+ x(其中x是向量的索引)。
或者,使用一个集合,其迭代器不会通过插入而失效。对此最好的是列表。列表由小块内存(每个项目1个)构成,并带有指向下一个块的指针。这使得插入非常快速和简单,因为不需要修改内存,只需指向新项目两侧的块的指针。你的迭代器仍然有效!
擦除是一样的,除非你删除你的迭代器引用的项目,它的无效(显然),所以你不能对它进行任何操作。甚至++运算符也不会工作,因为向量中的内存可能已更改,或者列表指针不同。因此,您可以先获取下一个元素的迭代器,存储它,然后在删除项目后使用它,或者使用erase()方法中的返回值。
答案 3 :(得分:0)
如果您使用list作为集合而不是vector,则不会获得随机访问权限,并且可能会使用更多内存,但您可能会在集合中间插入常量时间,这样做不会使您失效迭代器。
例外是你要擦除的那个,所以你不能在循环结束时使用它。您必须通过存储其下一个元素的副本来处理这种情况。