我是共享指针的新手,我正试图从图中删除一个节点。删除节点时,将删除存储在该节点中的传入和传出边缘。但是,我还需要删除先前连接到已删除节点的节点的传出和传入边缘(分别是已删除节点的传入和传出边缘) - 我称之为链接节点。
下面的代码显示了我的Graph类声明:
template <typename N, typename E> class Graph {
private:
struct Node;
struct Edge;
struct Node {
N val_;
int numEdges_;
int numIncomingEdges_;
std::set<std::shared_ptr<Edge>> edges_;
std::set<std::shared_ptr<Edge>> incomingEdges_;
Node() {}
Node(const N x) : val_{x} { numEdges_=0; }
void printNode(N n);
~Node();
void update();
};
struct Edge {
std::weak_ptr<Node> orig;
std::weak_ptr<Node> dest;
E val_;
Edge(std::shared_ptr<Node> o, std::shared_ptr<Node> d, E x);
Edge() {};
void printEdge();
~Edge();
};
..... Some code for node and edge iterators
private:
std::map< N, std::shared_ptr<Node> > nodes_;
};
要删除节点的类:
template <typename N, typename E>
void Graph<N, E>::deleteNode(const N& node) noexcept {
auto findNode = nodes_.find(node);
if (findNode != nodes_.end()) {
// find the node which has incoming edges into the deleted node and delete its edges
for (auto edge: findNode->second->incomingEdges_) { // for each edge in node's incomingEdges_
// get the origin node of incoming edge to deleted node through dest.lock()
auto originNodeOfIncomingEdge = edge->dest.lock();
auto nodeVal1 = originNodeOfIncomingEdge->val_;
std::cout << "Print out value of origin node of incoming edge to deleted node: " << nodeVal1 << std::endl;
auto findLinkingNode1 = nodes_.find(nodeVal1);
std::cout << "size of edges_ in linking node before deleting its outgoing edge (which is the incoming edge of deleted node): " << findLinkingNode1->second->edges_.size() << std::endl;
auto findEdge = findLinkingNode1->second->edges_.find(edge);
findLinkingNode1->second->edges_.erase(findEdge);
std::cout << "size of edges_ in linking node after deleting its outgoing edge (which is the incoming edge of deleted node): " << findLinkingNode1->second->edges_.size() << std::endl;
--findLinkingNode1->second->numEdges_;
}
... similar code to above for deleting the node that has outgoing edges from deleted node going into it
findNode->second.reset(); // deletes managed object of the shared_ptr
nodes_.erase(findNode); // removes the node from the map container
}
}
所以令我困惑的主要是这部分,我试图从for循环中删除边缘以删除链接节点中的边缘。
auto findEdge = findLinkingNode1->second->edges_.find(edge);
findLinkingNode1->second->edges_.erase(findEdge);
但是我一直在收到与shared_ptr相关的错误。首先与指针有关:
test8c(2863,0x7fff78df2000) malloc: *** error for object 0x7ffda2403350: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
以前,我的代码是findLinkingNode1->second->edges_.erase(edge);
而没有findEdge。我能够编译没有任何错误,但边缘没有被删除。
有人可以指导我如何成功删除edge_的边缘? edges_声明为std::set<std::shared_ptr<Edge>> edges_;
,如Graph类所示。
答案 0 :(得分:0)
事物的结构方式,效率不高。你的Node
析构函数需要:
对正在销毁的Edge
中的每个Node
进行迭代。
对于每个Edge
get()
其他Node
。
在其他Edge
列表中找到相同的Node
,然后将其删除。
如果这是一个频繁的操作,我建议进行以下重构:
Edge
暂挂shared_ptr
Node
s。
Node
暂挂weak_ptr
Edge
s。
因此,要删除Node
,请迭代节点的Edge
,然后删除它们。删除所有Edge
后,shared_ptr
的{{1}}超出范围,节点将被销毁。
如果这是不切实际的,那么重新设计就不那么激烈了:
为每个Node
分配一种唯一的标识符。一个简单的递增计数器就可以了,并且可以自动在Edge
的构造函数中处理它。
使用其唯一标识符引用您的所有Edge
,而不是使用Edge
std::set
个shared_ptr
s替换它标识符Edge
,std::map
shared_ptr
。在销毁特定Edge
时,这会使从Edge
删除每个Node
变得微不足道。
不是实现离散标识符,而是可以使用Node
的原始指针,Edge
作为严格的弱排序比较器,作为每个的即兴唯一标识符。边缘。