多个共享_ptr,指向同一对象

发布于 2025-02-12 08:15:08 字数 2095 浏览 0 评论 0原文

仅出于学习目的,我正在编码二进制搜索树轮换。 我通常使用std :: unique_ptr,但是我使用std :: shardy_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;
  }

cppreference:

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说: link

std :: shared_ptr是一个智能指针,通过指针保留对象共享所有权。几个共享_ptr对象可以拥有相同的对象。当两个发生以下任何一个时,该对象被破坏,其内存被划分:

  • 剩下的剩下的共享_ptr拥有该对象;
  • 最后剩下的shared_ptr拥有该对象是通过operator =或reset()。
  • 分配了另一个指针。

为了避免在分配之前销毁由x指向的节点,我创建了另一个std :: shardy_ptr&lt; node&gt;拥有*x,但在第二个实现是在调用x指向的节点对象之前已经销毁了y-&gt; left_ = x_ptr。当一个root_ = yxp-&gt; left_ = yxp-&gt; right_ = y is时称为。

显然有多个std :: shared_ptr拥有同一节点对象的对象。 root _xp-&gt; left _xp-&gt; right _显然不是最后剩下的剩下的std :: shardy_ptr拥有对象。为什么会发生这种情况?

Just for studying purpose I'm coding binary search tree rotation now.
I normally use std::unique_ptr but I used std::shared_ptr this time

This works correctly:

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

This crashes:

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 says: Link

std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of the following happens:

  • the last remaining shared_ptr owning the object is destroyed;
  • the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset().

To avoid destroying the node pointed to by x before assigning, I created another std::shared_ptr<Node> that owns *x, but in the second implementation, the node object pointed by x is already destroyed before y->left_ = x_ptr is called. The node object is actually destroyed when one of root_ = y, xp->left_ = y and xp->right_ = y is called.

There are clearly multiple std::shared_ptr objects that own the same node object. root_, xp->left_ or xp->right_ is clearly NOT the last remaining std::shared_ptr owning the object. Why this happens?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月光色 2025-02-19 08:15:08
void left_rotate(Node *xp, Node* x) {
    ...
    std::shared_ptr<Node> x_ptr(x);
    ...

创建shared_ptr时,它接管了x的所有权。这里的问题在于,不是您的。其他人,另一个shared_ptr,已经拥有指针的所有权。因此,您在y-&gt; 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 _也是sharone_ptr

void left_rotate(Node *xp, Node* x) {
    ...
    std::shared_ptr<Node> x_ptr(x);
    ...

When you create the shared_ptr it takes over ownership of x. The problem here is that it is not yours to give. Someone else, another shared_ptr, already has ownership of the pointer. So some of the operations you do before y->left = xptr will assign a new value to the shared_ptr owning x and that deletes the x.

The problem is that you use raw pointers as arguments. Whenever you extract the pointer from a shared_ptr be very careful about the lifetime of the object. The extracted raw pointer does not keep the object alive. Something that becomes exceedingly difficult to reason about with function calls. Easy to mess up as you experienced.

It's easily avoided by passing shared_ptr as arguments because they will keep your objects alive:

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

PS: I hope your root_ is a shared_ptr too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文