簡體   English   中英

為什么重命名變量可以防止段錯誤?

[英]Why does renaming my variable prevent a segfault?

我有一個深度優先的搜索算法可以遍歷我的圖,給定迭代器到起始節點。

文檔摘要:

  • GraphIterGraph::iteratortypedef
  • 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()迭代。

可能是start->second.edges()通過值返回std::set<std::string> 這將導致循環中的迭代器不兼容,並導致不確定的行為。

您的“魔術”

set<string> edges = start->second.edges();

確保您在同一容器“ edges”上進行迭代。

您可以通過讓Node::edges()通過引用返回來修復它:

const std::set<std::string>& edges() const { .... }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM