我有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);
}
但仍在计算父母将导致原始根节点。所以我无法创建子树。
我觉得将shared_ptr
用于Tree
和TreeNode
是错误的,但这不是我的代码。我只需要添加一个功能。
答案 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
用于Tree
和TreeNode
我分享你的感受。当然,当节点有一个父指针时,不清楚如何在多个树之间明智地共享节点。
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;
}