在包含共享指针列表的共享指针后面复制对象

copy object behind shared pointer containing a list of shared pointers

我有一个 shared_ptr<Tree> tree 和一个 shared_ptr<TreeNode> node,其中包含子列表作为共享指针。

class TreeNode
{
protected:
    std::weak_ptr<TreeNode> parent;

    /**
    A list containing the children of this node
    */
    std::shared_ptr<std::vector<std::shared_ptr<TreeEdge>>> children;

   ...

一棵树只需要给定一个 TreeNode 作为它的根。

Tree::Tree(const shared_ptr<TreeNode> root)
    : root(root)
{}

因此,为了创建该子树,我尝试获取一个 TreeNode 并使用它调用 Tree 构造函数。

shared_ptr<TreeNode> treeNode = oldTree->getASpecialNode();
shared_ptr<Tree> newTree = make_shared<Tree>(treeNode);

现在 newTree 的根是 treeNode。但问题是,每个 TreeNode 都指向其父节点。 treeNode.

也是
weak_ptr<TreeNode> TreeNode::getParent() const
{
    return parent;
}

当通过 newTree 中任何 TreeNode 的父节点计算根节点时,我们将到达与 newTreeNode 不同的根节点,因为 newTreeNode 本身有一个父节点。

删除该父级不是解决方案,因为该对象是共享的,我们将在原始树中需要它。所以我看到的唯一解决方案是复制 TreeNode 并复制它的所有成员。

我该怎么做?

基于 SO 上的其他答案,我尝试了这个:

std::shared_ptr<TreeNode> TreeNode::clone() const
{
    auto clone = new TreeNode (*this );
    clone->setParent(weak_ptr<TreeNode>());
    return shared_ptr<TreeNode>(clone);
}

但是还是计算父节点会导致原来的根节点。所以我无法创建子树。

我感觉TreeTreeNode使用shared_ptr是错误的,但这不是我的代码。我只需要添加一个功能。

您的克隆函数应该类似于:

std::shared_ptr<TreeNode> TreeNode::clone() const
{
    auto res = std::make_shared<TreeNode>();

    for (auto child : *children) {
        res->AddChild(child->clone());
    }
    return res;
}

必须克隆整个子树,而不仅仅是子根。由于 none 的指针被复制,因此复制初始化克隆是没有用的。此外,您应该避免使用指向已分配内存的裸指针,以保证强大的异常安全性。

未经测试的示例:

std::shared_ptr<TreeNode> TreeNode::clone() const
{
    auto clone = std::make_shared<TreeNode>();
    clone->children->reserve(children->size());
    for(const auto& c : *children) {
        auto c_clone = c->clone();
        c_clone->setParent(clone);
        clone->children->push_back(c_clone);
    }
    return clone;
}

I have the feeling that it's wrong to use shared_ptr for Tree and TreeNode

分享你的感受。当然,当节点有一个父指针时,不清楚如何在多棵树之间明智地共享节点。

std::shared_ptr<std::vector<std::shared_ptr<TreeEdge>>> 也显得过于间接了。