多个shared_ptr指向同一个对象

问题描述 投票:0回答:1

出于学习目的,我现在正在编码二叉搜索树旋转。 我通常用

std::unique_ptr
,但这次我用
std::shared_ptr

这工作正常:

// Node implementation
template <Containable T = int> struct Node {
  T key_ = T{};
  bool black_ = false; // red-black tree
  std::shared_ptr<Node> left_;
  std::shared_ptr<Node> right_;
};

// this is a protected member function of red-black tree class
// xp is parent node of x
void left_rotate(Node *xp, Node* x) {
    assert(x);
    auto y = x->right_;
    x->right_ = y->left_;
    std::shared_ptr<Node> x_ptr;
    if (!xp) {
      x_ptr = root_;
      root_ = y;
    } else if (x == xp->left_.get()) {
      x_ptr = xp->left_;
      xp->left_ = y;
    } else {
      x_ptr = xp->right_;
      xp->right_ = y;
    }
    y->left_ = x_ptr;
  }

这会崩溃:

void left_rotate(Node *xp, Node* x) {
    assert(x);
    auto y = x->right_;
    x->right_ = y->left_;
    std::shared_ptr<Node> x_ptr(x);
    if (!xp) {
      root_ = y;
    } else if (x == xp->left_.get()) {
      xp->left_ = y;
    } else {
      xp->right_ = y;
    }
    y->left_ = x_ptr;
  }

cppreference 说:链接

std::shared_ptr
是一个智能指针,通过指针保留对象的共享所有权。多个shared_ptr对象可能拥有同一个对象。当发生以下任一情况时,该对象将被销毁并释放其内存:

  • 拥有该对象的最后剩余的shared_ptr被销毁;
  • 拥有该对象的最后一个剩余的shared_ptr通过operator=或reset()分配另一个指针。

为了避免在分配之前破坏

x
指向的节点,我创建了另一个拥有
std::shared_ptr<Node>
*x
,但在第二个实现中,
x
指向的节点对象在调用
y->left_ = x_ptr
之前就已经被破坏了。当调用
root_ = y
xp->left_ = y
xp->right_ = y
之一时,节点对象实际上被销毁。

显然有多个

std::shared_ptr
对象拥有相同的节点对象。
root_
xp->left_
xp->right_
显然不是最后一个拥有该对象的
std::shared_ptr
。为什么会出现这种情况?

c++ smart-pointers
1个回答
2
投票
void left_rotate(Node *xp, Node* x) {
    ...
    std::shared_ptr<Node> x_ptr(x);
    ...

当您创建

shared_ptr
时,它会接管
x
的所有权。这里的问题是,这不是你可以给予的。其他人,另一个
shared_ptr
,已经拥有了指针的所有权。因此,您在
y->left = xptr
之前执行的一些操作将为拥有
shared_ptr
x
分配一个新值,并删除
x

问题在于您使用原始指针作为参数。每当您从

shared_ptr
中提取指针时,都要非常小心该对象的生命周期。提取的原始指针不会使对象保持活动状态。对于函数调用来说,一些事情变得极其难以推理。正如您所经历的那样,很容易搞砸。

通过传递

shared_ptr
作为参数可以轻松避免这种情况,因为它们会让你的对象保持活动状态:

void left_rotate(std::shared_ptr<NodeY> xp, std::shared_ptr<Node> x) {

PS:我希望你的

root_
也是
shared_ptr

© www.soinside.com 2019 - 2024. All rights reserved.