【问题标题】:How to break shared_ptr cyclic reference using weak_ptr如何使用weak_ptr打破shared_ptr循环引用
【发布时间】:2015-01-21 00:58:16
【问题描述】:

我读过weak_pointers 可以用来打破循环引用。

考虑下面的循环引用示例

struct A
{
boost::shared_ptr<A> shrd_ptr;
};


boost::shared_ptr<A> ptr_A(boost::make_shared<A>());
boost::shared_ptr<A> ptr_b(boost::make_shared<A>());
ptr_A->shrd_ptr = ptr_b;
ptr_b->shrd_ptr = ptr_A;

以上是循环引用的例子,我想知道如何破解 上面的循环引用使用weak_ptr ?

更新: 根据收到的建议,我提出了以下建议:

struct A
{
  boost::weak_ptr<A> wk_ptr;
};

    boost::shared_ptr<A> ptr_A (boost::make_shared<A>());
    boost::shared_ptr<A> ptr_B (boost::make_shared<A>());
    ptr_A->wk_ptr = ptr_B;
    ptr_B->wk_ptr = ptr_A;

这会是正确的方法吗?

【问题讨论】:

  • A::shrd_ptr 更改为 boost::weak_ptr 并在其他地方按住 shared_ptr

标签: c++ smart-pointers c++03


【解决方案1】:

循环引用的经典示例是您有两个类AB,其中A 引用了B,而B 引用了A

#include <memory>
#include <iostream>

struct B;
struct A {
  std::shared_ptr<B> b;  
  ~A() { std::cout << "~A()\n"; }
};

struct B {
  std::shared_ptr<A> a;
  ~B() { std::cout << "~B()\n"; }  
};

void useAnB() {
  auto a = std::make_shared<A>();
  auto b = std::make_shared<B>();
  a->b = b;
  b->a = a;
}

int main() {
   useAnB();
   std::cout << "Finished using A and B\n";
}

如果两个引用都是shared_ptr,则表示A 拥有B 的所有权,而B 拥有A 的所有权,这应该会敲响警钟。换句话说,A 保持 B 存活,B 保持 A 存活。

在本例中,ab 实例仅在 useAnB() 函数中使用,因此我们希望它们在函数结束时被销毁,但正如我们在运行程序时看到的那样,析构函数不是调用。

解决方案是决定谁拥有谁。假设A 拥有BB 不拥有A,那么我们将B 中对A 的引用替换为weak_ptr,如下所示:

struct B {
  std::weak_ptr<A> a;
  ~B() { std::cout << "~B()\n"; }  
};

然后,如果我们运行程序,我们会看到 ab 已按预期销毁。

Live demo

编辑:在您的情况下,您建议的方法看起来非常有效。将所有权从A 手中夺走,而其他东西拥有As。

【讨论】:

  • 如果我们稍后从 a.lock() 创建 shared_ptr,问题(循环引用)是否仍然存在?
  • @Explorer_N 提供B 不会永久保留从a.lock() 创建的shared_ptr,那么就可以了。 Here is an expanded version of the live demo 包含使用 a.lock() 的示例。
  • Chris,怎么样,创建 shared_ptr 会增加托管对象的引用计数吗?我还将auto sa = a.lock(); 更改为static shared_ptr&lt;A&gt; sa;,但效果很好.....我想知道。
  • @Explorer_N 是的,auto sa = a.lock() 将增加 a 的引用计数,但当 sa 超出范围时引用计数将再次减少,这很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
  • 1970-01-01
相关资源
最近更新 更多