我有一个深度优先的搜索算法可以遍历我的图,给定迭代器到起始节点。
文档摘要:

  • GraphIterGraph::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/

    10-11 17:05