我正在用C ++编写有向图。如果我使用某个使用异常处理的特定函数初始化它们,则图节点的邻接列表中的图形节点指针会损坏,但是如果使用不使用异常处理的类似函数对其进行初始化,则这些列表指针不会损坏。>
我的图类具有以下标题的函数:
bool directed_edge(const Key& parent, const Key& child) throw(std::invalid_argument);
...以及带有此标题的另一个功能:
std::tuple<bool, bool, bool> add_directed_edge(const Key& parent, const Key& child);
如果当前图形中没有directed_edge
或parent
,则 child
会引发异常。 add_directed_edge
通过调用directed_edge
来工作,并通过将节点实际添加到列表中并然后将它们与边连接来处理异常。
如果使用directed_edge
创建边,则根本没有数据损坏-图形节点的邻接表包含预期的数据。但是,如果我使用add_directed_edge
,则数据已损坏。这很奇怪,因为add_directed_edge
除了调用directed_edge
并处理它可能引发的任何潜在错误之外,实际上并没有做很多事情。这使我相信它与函数内部的异常处理有关,但是我不确定。
这是两个功能的实现:
template<typename Key>
bool graph<Key>::directed_edge(const Key& parent, const Key& child) throw(std::invalid_argument)
{
node* parentItor = find_node(parent);
node* childItor = find_node(child);
// Return true if the edge was added
return parentItor->directed_edge(childItor);
}
template<typename Key>
std::tuple<bool, bool, bool>
graph<Key>::add_directed_edge(const Key& parent, const Key& child)
{
bool parentAdded;
bool childAdded;
bool edgeAdded;
// Try to add the directed edge. Exception thrown if either doesn't exist
try {
edgeAdded = directed_edge(parent, child);
return std::make_tuple(false, false, edgeAdded);
}
catch(std::invalid_argument& invArg) {
// Add parent and child, and assign to see if they needed to be added
parentAdded = add(parent);
childAdded = add(child);
// Add the directed edge
edgeAdded = directed_edge(parent, child);
return std::make_tuple(parentAdded, childAdded, edgeAdded);
}
}
我意识到这两个功能都在调用其他功能的 lot ,因此,如果您想了解更多实施细节,可以发表评论,我会尽快与您联系>
我用一些基本数据进行了三个测试。在第一个测试中,我手动添加了节点0-9,然后使用directed_edge
建立了一些连接。结果是这样的:
0 -> 1, 3
1 -> 2, 4, 6, 7
2 -> 3, 8, 9
3 ->
4 -> 6, 7, 5
5 ->
6 -> 7
7 ->
8 ->
9 ->
在第二个测试中,我没有手动向图中添加任何节点。我反复调用add_directed_edge
,因为该函数旨在在每次给不存在的节点提供密钥时添加节点。结果是这样的:
0 -> 284985109, 976560249
1 -> 1752440936, 116, 17504392, 7
3 ->
2 -> 1768366181, 8, 9
4 -> 6, 7, 5
6 -> 7
7 ->
8 ->
9 ->
5 ->
另外,为了更彻底,我进行了第三次测试,在该测试中,我手动添加了所有节点,然后调用add_directed_edge
在先前存在的节点上建立连接。有趣的是,这产生了预期的结果:
0 -> 1, 3
1 -> 2, 4, 6, 7
2 -> 3, 8, 9
3 ->
4 -> 6, 7, 5
5 ->
6 -> 7
7 ->
8 ->
9 ->
答案 0 :(得分:0)
如果您能够使用Valgrind或gcc / clang address-sanitizer之类的代码运行代码,那么它们通常是识别此类问题原因的好方法。
答案 1 :(得分:0)
您猜测问题add_directed_edge
中存在异常的假设被很好地猜测,但是是错误的。实际问题是,添加图节点会导致图中图节点的向量调整大小,从而使每个图的邻接表中的图节点指针无效
图类具有成员变量vector<graph_node<Key>> nodes
,并且每个图节点具有成员变量vector<graph_node<Key>*> adjacencyList
。每当在两个节点之间形成有向边时,您都将执行以下操作:nodes[i].adjacencyList.push_back(&nodes[j])
。这将使节点i
指向节点j
这是一个问题。每当需要调整向量&nodes[j]
的大小时,引用nodes
就会失效,因为在调整大小期间,nodes[j]
的数据会复制到内存中完全不同的位置。
This网页上有关于容器的更多信息-您应仔细阅读标题为“迭代器无效”的部分。看到我看到的了吗?对于向量,如果调整内部数组的大小,则所有迭代器(即所有指针)都将失效。
如果您坚持要在节点上使用 pointers 的邻接列表,则应使用带有更稳定迭代器的STL容器,例如列表或地图