Reputation: 4106
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
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
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