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

时间:2017-09-27 09:49:04

标签: c++ c++11 shared-ptr deep-copy

我有shared_ptr<Tree> treeshared_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);
}

但仍在计算父母将导致原始根节点。所以我无法创建子树。

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

2 个答案:

答案 0 :(得分:1)

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

未经测试的例子:

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;
}
  

我觉得将shared_ptr用于TreeTreeNode

是错误的

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

std::shared_ptr<std::vector<std::shared_ptr<TreeEdge>>>似乎也过度间接。

答案 1 :(得分:0)

您的克隆功能应如下所示:

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

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