我有一个深度优先的搜索算法可以遍历我的图,给定迭代器到起始节点。
文档摘要:
GraphIter
是Graph::iterator
的 typedef Graph
类扩展了 map<string, Node>
start->second.edges()
返回set<string>
如果
start->second.edges()
的大小为 0 ,则此代码会导致分段错误:(为简洁起见,我将不相关的部分(包括递归调用)删节了。)
错误代码
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);
}
}
因此不同之处在于,在好的代码中,当字符串集的大小(来自
edges()
方法)为 0 时,在第二种情况下永远不会进入for
循环。但是在第一种情况下,for
循环仍然至少执行一次,直到它意识到无法取消引用it
变量为止。为什么这些不同?他们不访问内存的相同部分吗?
最佳答案
因为edges()
按值返回set
,所以start->second.edges().begin()
和start->second.edges().end()
将迭代器返回到不同的容器,因为每次调用edges()
都会导致返回新的set
。
通过使用命名变量创建单个副本,可以确保所有迭代器都来自同一容器,并且可以有效地从begin()
迭代到end()
。
关于c++ - 为什么重命名变量可以防止段错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11703422/