【发布时间】:2018-01-20 22:15:53
【问题描述】:
我在 C++ 中实现了一个二叉搜索树。我没有使用裸指针指向子节点,而是使用了std::shared_ptr。树的节点实现如下
struct treeNode;
typedef std::shared_ptr<treeNode> pTreeNode;
struct treeNode {
T key;
pTreeNode left;
pTreeNode right;
treeNode(T key) : key(key), left(nullptr), right(nullptr) {}
};
当从 BST 中删除一个节点时,其中一种情况是该节点只有一个子节点。节点被这个孩子简单地替换,如下所示:
| remove node
node ---------> |
\ right
right
在类似的 Java 实现中,这可以编码为:
node = node.getRight();
在我的 C++ 实现中是:
node = node->right;
其中节点的类型为pTreeNode。
在 pTreeNode (std::shared_ptr<TreeNode>) 上调用 = 运算符时,将调用 node 的析构函数。指向底层TreeNode 的共享指针的数量为1,因此TreeNode 被销毁以释放其内存。当TreeNode(默认)析构函数被调用时,它的每个成员都会被销毁。这肯定会导致pTreeNode right 成员被销毁。问题是node->right 是分配给node 的内容。在测试我的 BST 时,它似乎工作正常,没有错误/内存泄漏。
- 我在做什么不安全吗?
- 如果不安全,我可以做些什么来解决这个问题?
我认为可能有效的“hack”是创建另一个指针以增加其引用计数。这会是一个适当的解决方案吗?
//increase reference to node->right by 1 so it doesn't get destroyed
pTreeNode temp(node->right);
node = node->right;
【问题讨论】:
-
我不熟悉共享指针。我的建议是查看析构函数是在赋值之前还是之后调用的。我的猜测是它是在之后调用的,这意味着有一个指向前
node->right的指针已经增加了引用计数。因此,子节点不会被破坏。 -
相关 Herb Sutter youtu.be/JfmTagWcqoE?t=887
-
@CaptainGiraffe 哇,我不知道有类似 shared_ptr alias ..using 的东西会阻止解决方法
-
shared_ptr可以安全使用...复制和移动操作已正确实施以按预期工作。所以只要你不使用原始的底层指针做奇怪的事情,代码应该可以正常工作。 -
没有什么可分享的,为什么还要使用shared_ptr?使用 unique_ptr。
标签: c++ c++11 binary-search-tree shared-ptr smart-pointers