[英]Why does accessing my capture-by-reference variable cause a segfault in my lambda function?
[英]Why does renaming my variable prevent a segfault?
我有一個深度優先的搜索算法可以遍歷我的圖,給定迭代器到起始節點。
文檔摘要:
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()
迭代。
可能是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.