我正在编写一些简单的连接组件代码并遇到一个奇怪的奇怪的段错误。
我的代码如下;首先是一些定义。
Node* node;
typedef std::pair<int, Node*> Edge;
struct Node {
...
std::list<Edge> neighbors;
...
}
段错误的代码如下:
if (node->neighbors.empty())
{
node->label = label_set.make();
}
else
{
Node* first_neighbor = node->neighbors.front().second;
node->label = first_neighbor->label;
int i = 0;
for (list<Edge>::iterator it = node->neighbors.begin(); it != node->neighbors.end(); it++)
{
i ++;
Node* n2 = (Node*)it->second;
node->label = label_set.merge(node->label, n2->label);
}
}
真正非常奇怪的是:
(lldb) p node->neighbors
(std::list<std::pair<int, _Node *>, std::allocator<std::pair<int, _Node *> > >) $4 = size=1 {
[0] = {
first = 78
second = 0x00d85520
}
}
(lldb) p *it
(std::pair<int, _Node *>) $8 = {
first = 0
second = 0xa0a45254
}
(lldb) p n2
(Node *) $5 = 0xa0a45254
看到这一点,我理解了段错误。 n2
设置为一个非常奇怪的值。它不在列表中;我没有正确迭代列表吗? n2
是否填充了随机数据,因为它超出了列表范围?但那么我的迭代是如何逃避界限的呢?我一无所知。
修改
我绝对不在列表范围内:在段错误i == 3
时。
EDIT2 它可能与我跟踪节点的方式有关吗?
答案 0 :(得分:1)
最好的猜测是,对label_set.merge
的调用会从node->neighbors
列表中删除当前节点,从而使it
迭代器无效。当它返回时,你试图递增迭代器以继续循环,但由于它已经失效(可能现在指向释放的内存),它会永远不会落地。
由于您没有显示label_set
是什么或merge
如何运作,因此无法分辨。
另一种可能性是你已经以某种方式破坏了堆,并且悬挂指针指向周围的方式,以便随意地覆盖事物。尝试使用valgrind运行,看看是否可以告诉您更多有关出错的信息。
答案 1 :(得分:1)
这可能是发生了什么:
如果您注释掉了调用label_set.merge
的for循环中的最后一行,那么您将留下一个简单的循环,该循环应该从std::list
开始到结束。
增量就在那里(即使完成++it
会更好,但那是另一个故事),加上你在循环中所做的一切就是检索{{1} }。但是,正如您声称的那样,您的循环将永远运行。
由于是这种情况,一个结论是it->second
无效或node
无效。您需要检查您的代码,以确保您不会错误管理内存或指针。使用智能指针而不是原始指针(甚至可能是
node->neighbors
如果节点指针确实在各种对象之间共享。)
对于调试器,您可以在无效对象中显示正常的值。可能发生的是调试器向您显示无效对象中各个成员的值。由于对象无效,因此这些值可以是任何值,包括合理的值。
编辑:
您在此处发布的链接:https://gist.github.com/noio/3082a0f351edb1821e90
显示您获取std::pair<int, std::shared_ptr<Node>>
中最后一项的地址。如果向量调整到更大的容量,这将是危险的,因为向量的迭代器将变为无效。不要保留指向向量中数据的指针值,除非您可以保证在您使用指针时不会调整向量的大小。