[英]SIGSEGV when using references of shared_ptr
You would get a SIGSEGV if you ran the following C++ code: 如果运行以下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;
}
I don't know why it crashes. 我不知道为什么会崩溃。 But I found that if I changed this line in the main function:
但是我发现,如果我在主要功能中更改了这一行:
std::shared_ptr<Node>& childNode = parentNode->childNodes[0];
to 至
std::shared_ptr<Node> childNode = parentNode->childNodes[0];
The problem would disappear. 问题将消失。 The program correctly output two zeros and exited safely, why?
程序正确输出两个零并安全退出,为什么? What caused the initial crash and why the modification could fix it?
是什么原因导致最初的崩溃,以及为什么修改可以解决该问题?
A push_back
into a vector invalidates all iterators, pointers and references to existing elements of the vector. 向量中的
push_back
会使向量的所有迭代器,指针和引用无效。
Since node
is a reference to an element of parentNode->childNodes
, pushing into it invalidates that reference. 由于
node
是对parentNode->childNodes
元素的引用,因此将其推入该元素会使该引用无效。 So merely accessing node->childNodes.size()
is undefined behavior. 因此,仅访问
node->childNodes.size()
是未定义的行为。
When you use a copy of the element in the vector, the node
reference remains valid because the shared_ptr
it refers to is still there, outside the storage the vector manages. 当您在向量中使用元素的副本时,
node
引用仍然有效,因为它所引用的shared_ptr
仍然存在于向量管理的存储器之外。
You can also avoid copying the shared_ptr
by simply passing a reference to the node itself. 您还可以通过简单地将引用传递给节点本身来避免复制
shared_ptr
。 Ie 即
void addChild(const Node &node, std::shared_ptr<Node> &parentNode)
Even if any shared_ptr gets reallocated, the reference to Node
will not be invalidated. 即使重新分配了任何shared_ptr,对
Node
的引用也不会无效。
When you push the newNode
here in addChild
: 当您在
addChild
中将newNode
推newNode
此处时:
parentNode->childNodes.push_back(newNode);
You may be invalidating the reference you took on main
to parentNode->childNodes[0]
, which in turn is called node
in addChild
. 你可能会失效,你承担了参考
main
以parentNode->childNodes[0]
而这又被称为node
中addChild
。
In the end, this results in an invalid read when you dereference node
in your problematic line: 最后,当您取消引用有问题的行中的
node
时,这将导致无效的读取:
node->childNodes
which triggers the segfault in turn. 依次触发段错误。
If, instead, you create a copy of parentNode->childNodes[0]
, everything is fine, because in this case you do not have any reference to any element of the childNodes
std::vector
, so none can go invalid. 相反,如果您创建了
parentNode->childNodes[0]
的副本,那么一切都很好,因为在这种情况下,您没有对childNodes
std::vector
任何元素的任何引用,因此任何元素都不会失效。
Note that the pointers themselves (the ones contained in your std::vector
s) are always fine, because they are never modified in either version (and when you create a copy of the std::shared_ptr
in the working case, everything works out on destruction as well due to the reference counting mechanics that std::shared_ptr
provides). 请注意, 指针本身(
std::vector
包含的指针 )总是很好的,因为它们在任何一个版本中都不会被修改(并且在工作情况下创建std::shared_ptr
的副本时,一切都会正常进行)以及由于std::shared_ptr
提供的引用计数机制而导致的破坏)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.