-1

I have 2 sets of pointers where I want to delete a certain pointer from. But it's giving me a double free error at the last line in the delete edge function.

I initially suspected that maybe it was because set::erase() was implicitly calling delete but I read some documents and found out that the destructor won't be called because edge_ins and edge_outs are both sets of pointers to Edges.

Now I'm not sure what is causing the double free error at the second call to set::erase() so I've come here for help.

I have a suspicion that it might be because pointers are treated like objects and when I erase the same pointer from root->edge_outs.erase(e) it's already gone so it crashes because of the second call at root->edge_ins.erase(e). But I was not able to find anything helpful so far.

Edge Deletion:

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);
}

Might be relevant so I will also add how I allocate the memory for the Edge.

Edge creation:

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;
}

UPDATE: I have changed the code so that I don't dereference a deleted object but it still gives a double free error.

New code:

SDG::delete_edge(std::set<Edge*>::iterator e)
{
    (*e)->head->rm_in(e);
    (*e)->root->rm_out(e);
    delete *e;
}
funnypig run
  • 182
  • 2
  • 9
  • You can't dereference pointer after you call `delete *e;`. So, erase it from sets first and then delete it. – Michael Nastenko Oct 13 '19 at 07:02
  • @MichaelNastenko I have tried changing my code as @jignatius has suggested. However, it still gives me an error `free(): double free detected in tcache 2` I have edited the question to add the changed code. – funnypig run Oct 13 '19 at 11:01

1 Answers1

0

Problem solved.

The problem was that this delete_edge function takes an std::set<Edge*>::iterator from edge_outs as an argument. Then proceeds to delete elements from another set which is edge_ins causing an undefined behavior that somehow leads to a double free.

To fix this, I have fundamentally changed the delete_edge function so that it takes a Edge* so that the user of the function does not get confused.

As for the return value, it was originally intended to be used to delete elements of edge_outs as the program iterated through it. So I needed a loop that uses iterator = edge_outs.erase(iterator) but I also wanted delete the same element from edge_ins at the same time. Thus, I came up with a function that ensures that the edge is deleted properly but it seems that I have failed at my first attempt.

Here is the better version of the function:

void
SDG::delete_edge(Edge* e)
{
    e->head->edge_ins.erase(e);
    e->root->edge_outs.erase(e);
    delete e;
}

When using this function, before the fix it was used like this:

iterator = delete_edge(iterator)

but I realized it has the same effect after the fix when you do as follows:

delete_edge(*(iterator++))

funnypig run
  • 182
  • 2
  • 9