在迭代时修改数据结构

时间:2011-04-12 16:09:58

标签: c++ stl iteration

将元素添加到数据结构(例如向量)时会发生什么 迭代它。我可以不这样做吗?

我尝试了这个并打破了:

int main() {
    vector<int> x = { 1, 2, 3 };

    int j = 0;
    for (auto it = x.begin(); it != x.end(); ++it) {
        x.push_back(j);
        j++;
        cout << j << " .. ";
    }
}

6 个答案:

答案 0 :(得分:15)

某些修改std::vector的操作会使迭代器失效。

其他容器有关于迭代器何时失效以及未失效的各种规则。 This is a post(由您真实地)提供详细信息。

顺便说一句,入口点函数main() 必须 返回int

int main() { ... }

答案 1 :(得分:11)

  

在迭代数据结构时将元素添加到数据结构(例如向量)时会发生什么。我不能这个吗?

如果向量调整自身,迭代器将变为无效。只要向量不自行调整大小,你就是安全的。

我建议你避免这种情况。

为什么调整大小会使迭代器失效的简短解释:

最初,向量具有一定的容量(通过调用vector::capacity()可以知道。),然后向其中添加元素,当它变满时,它会分配更大的内存,复制旧的元素内存到新分配的内存,然后删除旧内存,问题是迭代器仍然指向已经解除分配的旧内存。这就是调整大小使迭代器失效的方法。

这是简单的演示。只需查看capacity更改时间:

std::vector<int> v;
for(int i = 0 ; i < 100 ; i++ )
{
  std::cout <<"size = "<<v.size()<<", capacity = "<<v.capacity()<<std::endl;
  v.push_back(i);
}       

部分输出:

size = 0, capacity = 0
size = 1, capacity = 1
size = 2, capacity = 2
size = 3, capacity = 4
size = 4, capacity = 4
size = 5, capacity = 8
size = 6, capacity = 8
size = 7, capacity = 8
size = 8, capacity = 8
size = 9, capacity = 16
size = 10, capacity = 16

请在此处查看完整输出:http://ideone.com/rQfWe

注意: capacity()告诉矢量可以包含的最大元素数而不分配新内存size()告诉元素数量当前包含的矢量。

答案 2 :(得分:2)

一般来说这是一个坏主意,因为如果向量调整大小,迭代器将变为无效(它将指针包装到向量的内存中)。

还不清楚你的代码究竟在尝试做什么。如果迭代器以某种方式没有变得无效(假设它被实现为索引),我希望你在那里有一个无限循环 - 永远不会达到结束,因为你总是添加元素。

假设你想循环遍历原始的元素,并为每个元素添加一个,一个解决方案是将新元素添加到第二个向量,然后在最后连接:

vector<int> temp;

// ...

// Inside loop, do this:
temp.push_back(j);

// ...

// After loop, do this to insert all new elements onto end of x
x.insert(x.end(), temp.begin(), temp.end());

答案 3 :(得分:1)

这样做并不是一个好主意。

您可以考虑在push_back之后需要调整矢量大小的情况。然后它需要被移动到更大的内存点,你的迭代器现在将无效。

答案 4 :(得分:0)

虽然您使用了vector作为示例,但还有其他stl容器可以推送元素而不会使迭代器失效。将元素推回到std :: list并不需要重新分配现有元素,因为它们不是连续存储的(列表包含通过指向下一个节点的链接在一起的节点),因此迭代器保持有效,因为它们内部指向的节点仍然驻留在同一地址。

答案 5 :(得分:0)

如果您需要这样做,您可以select ODRP.PAR, SUM(CASE WHEN ODRP.TYPEID IN (1) THEN ODRP.PLANQUANT ELSE 0 END) VALTWO , SUM(CASE WHEN ODRP.TYPEID IN (5,6) THEN ODRP.PLANQUANT ELSE 0 END) VALONE from TableOne ODRP inner join TableTwo LOC on ODRP.LOCID = LOC.LOCID and LOC.LOCNAME like '%_USD' group by ODRP.PAR 您可以添加的最大记录数。这将阻止向量需要调整大小,这应该可以防止崩溃