Resurrection
Resurrection

Reputation: 4106

Delete object managed by two shared_pointer instances when either is deleted

I have a directed graph model represented by Node and Edge classes. Each Node object holds pointers to all its outgoing AND incoming edges and each Edge object holds pointers to its origin and end (Node objects).

class Model
{
public:
    ~Model() 
    {
        for(Node *node : nodes)
            delete node;
    }

    QVector<Node*> nodes;
};

class Node
{
    public:
    ~Node
    {
            for(Edge *edge : from)
            {
                if(edge)
                {
                    edge->to->to.replace(edge, nullptr);      
                    delete edge;
                }
            }

            for(Edge *edge : to)
            {
                if(edge)
                {
                    edge->from->from.replace(edge, nullptr);
                    delete edge;
                }
            }
    }

    QVector<Edge*> from;
    QVector<Edge*> to;
};

class Edge
{
public:
    Node *from;
    Node *to;
};

So far I have it implemented using raw pointers like this. It is rather complicated and involves manually removing the pointer from the other side of the edge (for every edge) when the node is deleted.I would rather like using smart pointers to make it all a bit safer and cleaner.

However the fact that I need to delete the edge (and invalidate the pointer on the other side) for both sides makes it problematic. If I used shared pointers the edges would never get deleted (and the remaining reference would remain valid even when the other side is gone). If I used weak pointers I would in turn need to store the shared pointer somewhere else which would again become more complicated because I would need to look it up and get rid of it whenever either side gets deleted.

What I need is a "smart" pointer that will keep track of the pointee (like shared pointer) but delete its pointee when its internal counter drops to 1 (instead of 0) so that it invalidates itself (like weak pointer) without going out of scope.

Should I write it myself or is there another solution?

Upvotes: 2

Views: 130

Answers (2)

Christophe
Christophe

Reputation: 73376

Nodes

Every edge is referred to by at least two nodes. If no node refers to an edge, this edge is useless and can be deleted. This suggest that the pointers from node to edge should be shared_ptr<Edge>.

The pointer vector in Model should by the way be shared_ptr<Node>

Edges

The edge can exist only if the source and destination nodes exist, but nodes can exist without edges. This suggest that the pointer in edges to nodes should be weak_ptr<Node> from, to;

You can always check if from or to nodes were deleted with from.expired(). But you have no way round the proper way to remove the edge: removing its pointer from both sides, in which case, the destruction of the edge is triggered when no longer needed.

Upvotes: 1

jxh
jxh

Reputation: 70412

What you want to be able to do is invalidate all pointers to a Node instance if that instance is deleted. This implies you want a notion of self-ownership. Thus, all pointers to the Node should be weak pointers to a shared pointer managed by Model (or perhaps the Node itself).

Each Node can be made to only have weak pointers to neighboring nodes. An Edge can be made on demand as needed, and an Edge would also only consist of weak pointers.

Upvotes: 1

Related Questions