用普通引用而不是weak_ptr来打破循环依赖

时间:2018-07-03 10:42:27

标签: c++ reference smart-pointers weak-ptr

看看std::weak_ptr,我在几个地方看到它可以用来解决由于使用std::shared_ptr而产生的循环依赖引起的内存泄漏。例如,请参见以下两个已接受的答案:[1][2]

采用上一个引用的答案,建议的解决方法是:

#include <memory>
#include <iostream>

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

struct B {
  std::weak_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";
}

但是,这感觉有点过头了,为什么不简单地使用引用呢?我知道在此示例中b->a并未在构造函数中设置,因此引用不会真正切掉它,所以我的问题是:

  

是否有理由使用std::weak_ptr代替引用,如果   关键是要打破循环依赖关系,如果我们可以在   构造函数?

注意::我了解std::weak_ptr用来保存可以无效的引用的有用性。我的问题仅涉及仅在打破循环依赖时的用处。

3 个答案:

答案 0 :(得分:1)

这是一个稍作修改的功能:

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

如果oops->a是一个普通的指针或引用,您怎么知道它不再指向有效的对象呢?

答案 1 :(得分:1)

您不能检查引用(或普通指针)是否引用了现有对象,也不能“重置”引用,例如在分配中。

答案 2 :(得分:0)

  

我了解std::weak_ptr持有可被无效的引用的有用性。我的问题仅涉及仅在打破循环依赖时的用处。

好吧,如果您具有循环依赖关系(或者甚至没有),并且希望将对“主”对象的引用存储在其他位置,以便可以访问它,并且可以肯定知道该对象不会消失,而您可能想要这样做,那么是的,我只使用引用,因为:

  • 便宜
  • 这也许可以避免首先将主对象设为shared_ptr(而且它们本身非常昂贵)

最后,归结为设计对象以最佳地执行您需要它们执行的任何工作。当然,std::weak_ptr并不是每个少女祈祷的答案。