首页 > 解决方案 > 使用 shared_ptr 的引用时的 SIGSEGV

问题描述

如果您运行以下 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];

问题就会消失。程序正确输出两个零并安全退出,为什么?是什么导致了最初的崩溃以及为什么修改可以修复它?

标签: c++

解决方案


A push_backinto a vector 使所有迭代器、指针和对向量现有元素的引用无效。

由于node是对 的元素的引用parentNode->childNodes,因此推入它会使该引用无效。所以仅仅访问node->childNodes.size()是未定义的行为。

当您在向量中使用元素的副本时,node引用仍然有效,因为shared_ptr它所引用的仍然存在,在向量管理的存储之外。

您还可以shared_ptr通过简单地将引用传递给节点本身来避免复制。IE

void addChild(const Node &node, std::shared_ptr<Node> &parentNode)

即使任何 shared_ptr 被重新分配,对的引用Node也不会失效。


推荐阅读