I have a single depth-first search algorithm implemented to traverse my graph, given the iterator to a starting node.
Documentation summary:
GraphIteris a typedef forGraph::iteratorGraphclass extendsmap<string, Node>start->second.edges()returnsset<string>
This code causes a segmentation fault if the size of start->second.edges() is 0:
(I’ve truncated the irrelevant pieces, including the recursive calls, for brevity.)
Bad Code
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
}
}
Now watch what happens when I pull start->second.edges() into a local variable: no more segfault!
Here’s the code that doesn’t generate a segfault:
Good Code
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);
}
}
So the difference is that in the good code, when the size of the set of strings (from the edges() method) is 0, the for loop is never entered in the second case. But in the first case, the for loop is still executed at least once until it realize that it can’t dereference the it variable.
Why are these different? Don’t they access the same parts of memory?
Because
edges()returns asetby value,start->second.edges().begin()andstart->second.edges().end()return iterators to different containers because each call toedges()results in a newsetbeing returned.By creating a single copy with a named variable you ensure that the iterators all come from the same container and you can validly iterator from
begin()toend().