向量迭代器不兼容
我目前正在开发 C++ 图形库,现在陷入了运行时在调试模式下出现断言错误的问题。我还在这里查看了其他一些问题,但没有一个问题和答案能引导我找到解决方案。在阅读一些论坛后,我的印象是,发生此错误是因为一旦向量内容发生更改,迭代器就会变得无效。 (例如,当使用 erase()
时)但正如您在我的代码中看到的,我没有修改向量,只是进行迭代。
错误出现在我用 //ASSERTION
标记的行中。奇怪的是,neighbor_it
并不指向 (*vertex_it)->neighbors(
) 中的第一个对象,而是指向 0xfeeefeee
。通过代码进行调试时,我可以清楚地看到邻居向量至少包含一项。 neighbor_it
不应该指向这个向量中的第一个对象吗?
有关更多信息:m_vertices
是图中所有顶点的向量,vertex::neighbors()
返回边向量(具有指向邻居/目的地的指针)顶点)。在这个方法中,我想删除指向某个顶点的所有边。如果已找到并删除相应的边,则返回 true;如果没有指向 p_vertex 的边,则返回 false。
bool graph::remove_edges_pointing_to( vertex* p_vertex )
{
bool res = false;
std::vector<vertex*>::iterator vertex_it = m_vertices.begin();
// iterate through all vertices
while( vertex_it != m_vertices.end() )
{
// iterator on first element of neighbors of vertex
std::vector<edge*>::iterator neighbor_it = (*vertex_it)->neighbors().begin();
// iterate through all successors of each vertex
while( neighbor_it != (*vertex_it)->neighbors().end() ) //ASSERTION
{
if( (*neighbor_it)->dest() == p_vertex )
{
if( (*vertex_it)->remove_edge( *neighbor_it ) )
{
res = true;
}
}
neighbor_it++;
}
vertex_it++;
}
return res;
}
编辑:(解决方案)
好吧,这是我的新代码,可以正常工作。 remove_edge()
现在返回一个迭代器,指向从中删除边缘的向量中的下一个对象。此外,neighbors()
现在返回相应向量的引用。
bool graph::remove_edges_pointing_to( vertex* p_vertex )
{
bool res = false;
std::vector<vertex*>::iterator vertex_it = m_vertices.begin();
// iterate through all vertices
while( vertex_it != m_vertices.end() )
{
// iterator on first element of neighbors of vertex
std::vector<edge*>::iterator neighbor_it = (*vertex_it)->neighbors().begin();
// iterate through all successors of each vertex
while( neighbor_it != (*vertex_it)->neighbors().end() )
{
if( (*neighbor_it)->dest() == p_vertex )
{
neighbor_it = (*vertex_it)->remove_edge( *neighbor_it );
res = true;
}
else
{
neighbor_it++;
}
}
vertex_it++;
}
return res;
}
再次感谢您的回答! :)
I'm currently working on a graph library for C++ and now got stuck at a point where I get an assertion error in debug mode during runtime. I also had a look an some other question here on SO but none of the questions and answers lead me to a solution. After reading in some forums I have the impression that this error happens because iterators become invalid as soon as the vector content is changed. (for example when using erase()
) But as you can see in my code, I'm not modifying the vector, just iterating.
The error is in the line I marked with //ASSERTION
. The strange thing is that neighbor_it
doesn't point to the first object in (*vertex_it)->neighbors(
) but to 0xfeeefeee
. When debugging through the code I can clearly see that the neighbors-vector contains at least one item. Shouldn't neighbor_it
point to the first object in this vector?
For further information: m_vertices
is a vector of all vertices in a graph and vertex::neighbors()
returns a vector of edges (which have a pointer to the neighbor/destination vertex). In this method I want to remove all edges pointing to a certain vertex. Returns true if an according edge has been found and removed, false if there is no edge pointing to p_vertex
.
bool graph::remove_edges_pointing_to( vertex* p_vertex )
{
bool res = false;
std::vector<vertex*>::iterator vertex_it = m_vertices.begin();
// iterate through all vertices
while( vertex_it != m_vertices.end() )
{
// iterator on first element of neighbors of vertex
std::vector<edge*>::iterator neighbor_it = (*vertex_it)->neighbors().begin();
// iterate through all successors of each vertex
while( neighbor_it != (*vertex_it)->neighbors().end() ) //ASSERTION
{
if( (*neighbor_it)->dest() == p_vertex )
{
if( (*vertex_it)->remove_edge( *neighbor_it ) )
{
res = true;
}
}
neighbor_it++;
}
vertex_it++;
}
return res;
}
EDIT: (Solution)
Alright, here is my new code which works properly. remove_edge()
now returns an iterator to the next object in the vector it removed the edge from. In addition neighbors()
now returns a reference to the according vector.
bool graph::remove_edges_pointing_to( vertex* p_vertex )
{
bool res = false;
std::vector<vertex*>::iterator vertex_it = m_vertices.begin();
// iterate through all vertices
while( vertex_it != m_vertices.end() )
{
// iterator on first element of neighbors of vertex
std::vector<edge*>::iterator neighbor_it = (*vertex_it)->neighbors().begin();
// iterate through all successors of each vertex
while( neighbor_it != (*vertex_it)->neighbors().end() )
{
if( (*neighbor_it)->dest() == p_vertex )
{
neighbor_it = (*vertex_it)->remove_edge( *neighbor_it );
res = true;
}
else
{
neighbor_it++;
}
}
vertex_it++;
}
return res;
}
Thanks again for your answers! :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我的猜测是,鉴于您提供的有限上下文,
neighbours()
返回std::vector
的副本,而不是引用,即std ::向量<边缘*>&
。因此,在begin()
调用之后,临时对象被释放,并且获得的迭代器指向垃圾。My guess, given limited context you provided, is that
neighbours()
returns copy ofstd::vector<edge*>
, instead of reference, i.e.std::vector<edge*>&
. So afterbegin()
call temporary object is disposed, and obtained iterator points to rubbish.我猜想
remove_edge
修改了neighbor_it
的底层容器,从而使其无效,但如果没有看到更多代码,我无法确定。如果是这种情况,可能的解决方案是将迭代器返回到已删除元素之后的下一个元素,例如通过 std::vector::erase 完成的操作。
I would guess that
remove_edge
modifies the underlying container ofneighbor_it
, thereby invalidating it, but I cannot be certain without seeing more of your code.If this is a case, a possible solution would be to return an iterator to the next element after the deleted one, as done for instance by
std::vector::erase
.