【问题标题】:Plain reference instead of weak_ptr to break circular dependency普通引用而不是weak_ptr来打破循环依赖
【发布时间】:2018-07-03 10:42:26
【问题描述】:

看看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-&gt;a 没有在构造函数中设置,所以引用不会真正削减它,所以我的问题是:

是否有理由使用 std::weak_ptr 而不是引用 if 如果我们可以在 构造函数?

注意:我理解std::weak_ptr 用于保存可以失效的引用。我的问题只涉及当重点是打破循环依赖时的有用性。

【问题讨论】:

  • 确实有不止一种方法可以打破循环依赖。使用共享和弱指针更多的是所有权问题。在这种情况下,谁拥有 A 和 B。
  • 为了使问题更加集中,您可以比较引用和常量非拥有智能 ptr(不是智能 ptr 到 const)。

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


【解决方案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-&gt;a 是普通指针或引用,您怎么知道它不再引用有效对象?

【讨论】:

  • 我可以看到std::weak_ptr 在处理“不可验证”引用时的用处,作为悬空指针问题的解决方案。我的问题是关于它在打破循环依赖时的用处。
  • @user2891462 - 它引出了一个问题,如果他们没有共享所有权,为什么要使用共享指针。首选解决方案是weak_ptr,因为它是面向未来的。共享指针的副本往往会弹出。如果您要使用unique_ptr,那么确实不需要引入开销。一个原始指针就足够了。
  • @StoryTeller 它提出了一个问题,即为什么允许共享弹出以及如何将弹出视为未来证明。你有可以共享的数据结构吗?除非它们是只读的,否则我对此表示怀疑。
【解决方案2】:

您无法检查引用(或普通指针)是否引用了现有对象,并且您无法“重置”引用,例如在赋值中。

【讨论】:

  • 感谢您的回答。我添加了一条注释来解决这个问题:我知道std::weak_ptr 处理“无效”指针的有用性,但我的问题是关于一个不同的用例:打破循环依赖。
【解决方案3】:

我理解std::weak_ptr 对持有可以失效的引用很有用。我的问题只涉及当重点是打破循环依赖时的有用性。

好吧,如果你有一个循环依赖(或者即使你没有)并且你想在其他地方存储对“主”对象的引用,以便你可以访问它,并且你肯定知道那个对象不会消失,而您可能想要这样做,那么是的,我只会使用参考,因为:

  • 更便宜
  • 它可能会避免首先将主对象设为shared_ptr(而这些本身非常昂贵)

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

【讨论】:

    猜你喜欢
    • 2015-01-21
    • 1970-01-01
    • 2020-01-29
    • 1970-01-01
    • 2015-10-13
    • 1970-01-01
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多