【问题标题】:Why is std::vector iterator invalidation upon reallocation of other vector?为什么 std::vector 迭代器在重新分配其他向量时失效?
【发布时间】:2015-11-20 21:30:04
【问题描述】:

这与该主题的其他问题并不完全相同。我刚刚偶然发现了一些非常奇怪的事情,无法理解这是怎么发生的。

struct Edge{
    int vertex_a{ 0 };
    int vertex_b{ 0 };
};
typedef std::vector<Edge> EdgeList;

struct Vertex{
    std::vector<int> edge_indices;
};

typedef std::vector<Vertex> VertexList;

    void ContractEdge(int edge_index){
            static int iter = 0;
            ++iter;
            auto& edge = edge_list[edge_index];
            auto& vertex_a = vertex_list[edge.vertex_a - 1];
            auto& vertex_b = vertex_list[edge.vertex_b - 1];
            auto dead_vertex_index = edge.vertex_b;
            std::vector<int> self_edge_array;
            auto& indices = vertex_b.edge_indices;

            for (auto it = indices.begin(); it != indices.end();++it){
                auto current_index = *it;
                auto& edge_of_b = edge_list[current_index];
                if (edge_of_b.vertex_a == dead_vertex_index){
                    edge_of_b.vertex_a = edge.vertex_a;
                }
                if (edge_of_b.vertex_b == dead_vertex_index){
                    edge_of_b.vertex_b = edge.vertex_a;
                }
                if (edge_of_b.vertex_a == edge_of_b.vertex_b){
                    self_edge_array.push_back(current_index);
                }
                else{
//this is the line where reallocation happens
                    vertex_a.edge_indices.push_back(current_index);
                }
            }
            RemoveVertexFromGraph(dead_vertex_index);
            int d = 0;
            for (auto& x : edge_list){
                if ((x.vertex_a > vertex_list.size()) || (x.vertex_b > vertex_list.size()))
                    ++d;
            }
            if (d)
                ++d;

            std::sort(self_edge_array.rbegin(), self_edge_array.rend());
            for (auto self_edge : self_edge_array){
                RemoveEdgeFromGraph(self_edge);
            }
        }

在这个函数的中间,我正在迭代一个顶点的索引向量,并偶尔将一些值 push_back 到另一个顶点的索引向量。

在运行此代码时,我开始收到错误消息“Vector iterator not icrementable”。 我决定再仔细调试一下,发现当我在vertex_a.edge_indices.push_back(current_index)这里做了一定数量的push_backs,并且vector的大小和容量都是19时,vector实现调用了_Reserve(1)方法,它调用了一些重新分配方法。 之后,索引向量会自动重新分配,其中的所有指针都指向另一个内存块。这就是为什么 auto it 迭代器不能进行比较,也不能增加,因为指向错误的地方它变得无效。

【问题讨论】:

  • 问题是?
  • 您可能会问为什么std::vector 不通过realloc 扩展其当前分配,而是在需要时分配新内存?
  • 有了这么多的间接性,您似乎已经设法退回到您正在遍历的向量上。如果您无法对其进行整理,请发布 complete(但请尽量少)示例。整理的提示:检查向量的地址,例如在调试器中,或通过跟踪输出语句。
  • 是的。似乎是这样。这个问题很明显,不是吗?它在标题中。所以。我怎么能 push_back 到另一个向量上?)
  • 你的代码太难理解了……你想做什么?

标签: c++ vector stl implementation realloc


【解决方案1】:

感谢您的 cmets。事实证明,在问题发生的那一刻,我实际上是在 push_back 反对我正在迭代的同一个向量。 当然,这会使迭代器无效。 所以问题出现在糟糕的数据组织和糟糕的编码风格上。 我现在正在查看您的 cmets,现在我明白我的代码非常糟糕。感谢您指出这一点。 我也没有将整个代码进行审查,因为我认为这已经足够了,但我确信我至少可以证明它是一个类并且它有一些成员。 并揭示更多结构。再次为此感到抱歉。 我想我可能需要想出一些其他的数据结构,也许在内部算法完成之前不做任何动态重新分配。我知道,0 和 1 索引也是蹩脚的。我只是在做一个课程任务,该任务在 txt 文件中,并且具有基于 1 的索引。

是的,d 和 iter 用于断点

【讨论】:

  • 在读/写文件时翻译这些索引可能更容易一些——以避免潜在的陷阱。不要让文件格式泄漏到您的表示中,除非它以某种方式有所帮助。此外,我认为您的代码并不像某些人所说的那样糟糕——正如所说,一个想要使用索引表示来表示邻接而不是指针的图结构不可避免地必须涉及很多更明确的间接(针对容器和索引)。对我来说,诀窍是不要混合迭代器,如果你喜欢那种风格——否则检查一个好的顺序/固定分配,并使用指针......
  • ...和单独分配的节点,至少在您真正熟悉这些结构的最低级别实现之前是这样。
猜你喜欢
  • 2011-04-14
  • 2017-04-15
  • 2012-06-13
  • 2019-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-17
  • 2019-08-31
相关资源
最近更新 更多