迭代,插入和删除?

时间:2010-11-03 18:21:22

标签: c++

梦想输出:

 /* 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;
 }

代码非常明显,但我想知道这里发生了什么。这是一个复制品,使用了一个更大的项目中发生的事情。这令我感到困惑。

4 个答案:

答案 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,则不会获得随机访问权限,并且可能会使用更多内存,但您可能会在集合中间插入常量时间,这样做不会使您失效迭代器。

例外是你要擦除的那个,所以你不能在循环结束时使用它。您必须通过存储其下一个元素的副本来处理这种情况。