開始ノードへのイテレータを指定して、グラフをトラバースするために単一の深さ優先探索アルゴリズムを実装しています。
ドキュメントの概要:
GraphIter
のtypedefですGraph::iterator
Graph
クラス拡張map<string, Node>
start->second.edges()
戻り値set<string>
のサイズが0の場合、このコードはセグメンテーション違反を引き起こしstart->second.edges()
ます。
(簡潔にするために、再帰呼び出しを含む無関係な部分を切り捨てました。)
悪いコード
void Graph::dfs(GraphIter start)
{
cout << "EDGES SIZE: " << start->second.edges().size() << endl;
for (set<string>::iterator it = start->second.edges().begin();
it != start->second.edges().end(); ++it)
{
GraphIter iter = this->find(*it); // <--- SEGMENTATION FAULT
}
}
start->second.edges()
ここで、ローカル変数をプルしたときに何が起こるかを見てください。これ以上のセグメンテーション違反はありません。
セグメンテーション違反を生成しないコードは次のとおりです。
良いコード
void Graph::dfs(GraphIter start)
{
set<string> edges = start->second.edges(); // <--- MAGIC TRICK
cout << "EDGES SIZE: " << edges.size() << endl;
for (set<string>::iterator it = edges.begin();
it != edges.end(); ++it)
{
GraphIter iter = this->find(*it);
}
}
したがって、違いは、適切なコードでは、 (メソッドからの)文字列のセットのサイズが0の場合、2番目のケースではループに入ることがないということです。ただし、最初のケースでは、変数を逆参照できないことがわかるまで、ループは少なくとも1回は実行されます。edges()
for
for
it
なぜこれらは違うのですか?彼らは記憶の同じ部分にアクセスしませんか?