用于向量向量的 c++ 迭代器
Posted
技术标签:
【中文标题】用于向量向量的 c++ 迭代器【英文标题】:c++ iterators for vector of vectors 【发布时间】:2013-06-16 14:04:08 【问题描述】:为什么会出现分段错误??
std::vector<std::vector<int> > cells;
std::vector<std::vector<int>::iterator> cellitr;
for(int i=0;i<10;i++)
std::vector<int> c;
std::vector<int>::iterator citr;
citr= c.begin();
for(int j=0;j<10;j++)
c.push_back(j);
cells.push_back(c);
cellitr.push_back(citr);
qDebug()<<cells[5][6];
int *x = &cells[5][6];
cells[5].insert(cellitr[5],200);//SEG FAULT HERE
qDebug()<<cells[5][6];
我有一个向量向量和迭代器向量,我正在尝试使用迭代器的索引在其中一个子向量中插入一个值。
有什么想法吗??
【问题讨论】:
您应该避免在这种情况下使用迭代器。它们太不稳定了。尝试保留索引。 但我需要在给定的索引中插入值而不仅仅是 push_back,如何在没有迭代器的情况下做到这一点?函数 insert 必须有一个迭代器作为输入 您可以使用v.begin()+index
为任何索引创建迭代器
【参考方案1】:
您的程序中有两个未定义行为的来源。
首先,当你这样做时:
c.push_back(j);
您正在增加向量的大小。如果向量的大小超过其容量,则向量必须重新分配更大的存储空间来保存其当前元素和新元素 - 这是因为向量必须始终将元素存储在连续的存储区域中。
发生重新分配时,迭代器无效。特别是,您的迭代器 citr
可能在插入之前以这种方式获得:
citr= c.begin();
将失效。取消引用无效的迭代器会在您的程序中注入未定义的行为。
第二,当你这样做时:
cellitr.push_back(citr);
您正在将迭代器存储到向量 (c
) 中,当循环退出时,该向量将超出范围 - 这将使存储的迭代器成为无效的迭代器。同样,取消引用无效的迭代器会给您带来未定义的行为。
为了避免这两种未定义行为的来源,您可以按如下方式更改循环:
cells.reserve(10);
for(int i=0;i<10;i++)
std::vector<int> c;
for(int j=0;j<10;j++)
c.push_back(j);
cells.push_back(c);
cellitr.push_back(cells.back().begin());
注意,在 C++11 中,您可以避免内部循环并使上述内容更紧凑:
#include <algorithm> // For std::iota() (C++11 only)
// ...
cells.reserve(10);
for(int i=0;i<10;i++)
std::vector<int> c(10);
std::iota(c.begin(), c.end(), 0);
cells.push_back(c);
cellitr.push_back(cells.back().begin());
【讨论】:
感谢您的出色回答,如果我需要在给定向量的给定索引中插入一个值,知道如何在没有迭代器的情况下执行此操作吗?? @AhmedKato:我扩展了答案:)【参考方案2】:这里,c
的 副本 被推送到 cells
:
cells.push_back(c);
在这里,您将迭代器存储到本地向量 c
,其生命周期仅为 for 循环的一次迭代:
cellitr.push_back(citr);
您将迭代器存储到本地向量中,并尝试在这些向量不存在的范围内访问它们。
除此之外,由于c
的增长,可能会出现一些迭代器失效问题。这可以通过调用c.reserve(10)
来解决,但您必须先解决另一个问题:
std::vector<int> c;
....
cellitr.push_back(cells.back().begin());
【讨论】:
以上是关于用于向量向量的 c++ 迭代器的主要内容,如果未能解决你的问题,请参考以下文章