SIGSEGV 使用shared_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
时:
parentNode->childNodes.push_back(newNode);
你可能会使你对parentNode->childNodes[0]
main
引用无效,这反过来在addChild
中被称为node
。
最后,当您取消引用有问题的行中的node
时,这会导致无效读取:
node->childNodes
这反过来触发段错误。
相反,如果您创建parentNode->childNodes[0]
的副本,一切都很好,因为在这种情况下,您没有任何对childNodes
std::vector
任何元素的引用,因此没有一个可以无效。
请注意,指针本身(包含在std::vector
中的指针(总是没问题的,因为它们在任何版本中都不会被修改(当您在工作案例中创建std::shared_ptr
的副本时,由于std::shared_ptr
提供的引用计数机制,一切都在销毁方面进行(。
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 引用 std::shared:ptr 以避免引用计数
- 如何控制共享 ptr 引用计数?
- 对唯一 ptr 无效读取的引用向量
- C++ 类型转换基础 PTR 到派生 PTR 保存在引用类中
- 为什么在将常量 ptr 分配给常量引用时没有收到编译错误?
- C 在多个引用上共享PTR发布
- 取消引用适用于 ptr->运算符*(),但不适用于 *ptr
- 在记录错误时取消引用 ptr 的设计是错误的
- 如何检测ptr在引用超出范围后是否仍在引用有效引用
- 在malloc()之后初始化结构中对ptr的引用
- 我应该通过引用、值或ptr来存储一个完全封装的成员吗
- 添加对共享ptr的引用会增加引用计数吗?
- 将字符串引用作为参数传递时Ptr错误
- 共享 PTR - C++ 如何使用引用计数管理对象缓存