用于向量向量的 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++ 迭代器的主要内容,如果未能解决你的问题,请参考以下文章

C++中的向量迭代器

向量迭代器不可取消引用 C++

c++迭代器在迭代向量时崩溃

C++:在开始之前不能寻找向量迭代器

对于 C++ Random Access Iterator(向量迭代器),迭代器之间的差异是如何计算的?

使用迭代器 C++ 删除对象类型的向量元素