我有2套指针,我想从中删除某个指针。但这在删除边缘功能的最后一行给了我一个双重释放错误。
我最初怀疑可能是因为set::erase()
隐式调用了delete
,但是我阅读了一些文档,发现因为edge_ins
和{{1 }}都是指向Edges的指针。
现在,我不确定是什么原因导致第二次致电edge_outs
时出现双重释放错误,所以我来这里寻求帮助。
我怀疑这可能是因为指针被当作对象对待,并且当我从set::erase()
擦除相同的指针时,它已经消失了,因此由于在root->edge_outs.erase(e)
的第二次调用而崩溃了。但是到目前为止,我找不到任何有用的东西。
边缘删除:
root->edge_ins.erase(e)
可能相关,因此我还将添加如何为Edge分配内存。
边缘创建:
std::set<Edge*>::iterator
SDG::delete_edge(std::set<Edge*>::iterator e)
{
delete *e;
(*e)->head->edge_ins.erase(e);
return (*e)->root->edge_outs.erase(e);
}
更新: 我已经更改了代码,以免取消引用已删除的对象,但仍然会出现双重释放错误。
新代码:
Edge&
SDG::edge(Vertex* out, Vertex* in, Edge::Type type)
{
// 新しいエッジを生成
Edge* edge = new Edge(type, *out, *in);
// 頂点からエッジへの参照
out->add_out(edge);
in->add_in(edge);
return *edge;
}
答案 0 :(得分:0)
您不应这样做:
delete *e; (*e)->head->edge_ins.erase(e); return (*e)->root->edge_outs.erase(e);
一旦删除了指针,您就不应尝试取消对其的引用,否则会遇到分段错误或某些其他未定义的行为。考虑像这样更改语句的顺序和delete_edge的返回类型:
void SDG::delete_edge(std::set<Edge*>::iterator e)
{
(*e)->head->edge_ins.erase(e);
(*e)->root->edge_outs.erase(e);
delete *e;
}
这将在删除指针本身之前从集合中删除指针。
您应该考虑使用智能指针(std::shared_ptr<Edge>
)代替原始指针。然后,您不必自己进行内存管理,即调用delete,因为内存将由智能指针管理。当销毁该资源的最后一个共享指针时,共享指针将删除堆上的内存。然后您可以像这样更改功能:
void SDG::delete_edge(std::set<std::shared_ptr<Edge>>::iterator e)
{
(*e)->head->edge_ins.erase(e);
(*e)->root->edge_outs.erase(e);
}
,并且集合应为std::set<std::shared_ptr<Edge>>
类型。这是如何创建共享指针的example。您可以在函数edge()中按如下方式创建它:
std::shared_ptr<Edge> edge = std::make_shared<Edge>(type, *out, *in);
使用共享指针将避免重复删除的问题,这似乎发生在您的代码中。否则,您必须自己进行内存管理,并避免两次删除指针。
答案 1 :(得分:0)
问题解决了。
问题在于此delete_edge
函数将std::set<Edge*>::iterator
中的edge_outs
用作参数。然后继续从另一组edge_ins
中删除元素,从而导致未定义的行为,从而导致双重释放。
要解决此问题,我从根本上更改了delete_edge
函数,使其采用了Edge*
,以使函数的用户不会感到困惑。
至于返回值,它最初打算用于在程序迭代时删除edge_outs
的元素。因此,我需要一个使用iterator = edge_outs.erase(iterator)
的循环,但我也想同时从edge_ins
中删除相同的元素。因此,我想出了一个功能,可确保正确删除边缘,但似乎我第一次尝试失败。
以下是该函数的更好版本:
void
SDG::delete_edge(Edge* e)
{
e->head->edge_ins.erase(e);
e->root->edge_outs.erase(e);
delete e;
}
使用此功能时,在修复之前,应像这样使用
: iterator = delete_edge(iterator)
但是当您执行以下操作时,我意识到修复后具有相同的效果:
delete_edge(*(iterator++))