[英]Avoiding indirect cyclic references when using shared_ptr and weak_ptr
[英]SIGSEGV when using references of shared_ptr
如果運行以下C ++代碼,您將獲得SIGSEGV:
#include <iostream>
#include <vector>
#include <memory>
class Node {
public:
std::vector<std::shared_ptr<Node>> childNodes;
};
void addChild(const std::shared_ptr<Node> &node, std::shared_ptr<Node> &parentNode) {
std::shared_ptr<Node> newNode = std::make_shared<Node>();
std::cout << node->childNodes.size() << std::endl;
parentNode->childNodes.push_back(newNode);
std::cout << node->childNodes.size() << std::endl; // the program crashes when running this line
}
int main(int argc, char *argv[]) {
std::shared_ptr<Node> parentNode = std::make_shared<Node>();
parentNode->childNodes.emplace_back(std::make_shared<Node>());
std::shared_ptr<Node>& childNode = parentNode->childNodes[0];
addChild(childNode, parentNode);
return 0;
}
我不知道為什么會崩潰。 但是我發現,如果我在主要功能中更改了這一行:
std::shared_ptr<Node>& childNode = parentNode->childNodes[0];
至
std::shared_ptr<Node> childNode = parentNode->childNodes[0];
問題將消失。 程序正確輸出兩個零並安全退出,為什么? 是什么原因導致最初的崩潰,以及為什么修改可以解決該問題?
向量中的push_back
會使向量的所有迭代器,指針和引用無效。
由於node
是對parentNode->childNodes
元素的引用,因此將其推入該元素會使該引用無效。 因此,僅訪問node->childNodes.size()
是未定義的行為。
當您在向量中使用元素的副本時, node
引用仍然有效,因為它所引用的shared_ptr
仍然存在於向量管理的存儲器之外。
您還可以通過簡單地將引用傳遞給節點本身來避免復制shared_ptr
。 即
void addChild(const Node &node, std::shared_ptr<Node> &parentNode)
即使重新分配了任何shared_ptr,對Node
的引用也不會無效。
當您在addChild
中將newNode
推newNode
此處時:
parentNode->childNodes.push_back(newNode);
你可能會失效,你承擔了參考main
以parentNode->childNodes[0]
而這又被稱為node
中addChild
。
最后,當您取消引用有問題的行中的node
時,這將導致無效的讀取:
node->childNodes
依次觸發段錯誤。
相反,如果您創建了parentNode->childNodes[0]
的副本,那么一切都很好,因為在這種情況下,您沒有對childNodes
std::vector
任何元素的任何引用,因此任何元素都不會失效。
請注意, 指針本身( std::vector
包含的指針 )總是很好的,因為它們在任何一個版本中都不會被修改(並且在工作情況下創建std::shared_ptr
的副本時,一切都會正常進行)以及由於std::shared_ptr
提供的引用計數機制而導致的破壞)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.