【问题标题】:shared_ptr, subscription, destructorshared_ptr、订阅、析构函数
【发布时间】:2009-12-18 20:04:56
【问题描述】:

我在整个应用程序中使用 Boost/shared_ptr 指针。当对对象的最后一个引用被释放时,shared_ptr 将为我删除该对象。应用程序中的对象订阅应用程序中心位置的事件,类似于观察者/订阅者模式。

在对象析构函数中,对象将从订阅列表中取消订阅。订阅列表本质上只是一个list<weak_ptr<MyObject> >。我想做的是类似于这样的事情:

Type::~Type()
{
  Subscriptions::Instance()->Remove(shared_from_this());
}

我的问题是无法在析构函数中调用 shared_from_this,所以上面的代码会抛出异常。

在我的旧实现中,订阅列表只是一个指针列表,然后它就起作用了。但我想改用weak_ptr 引用来降低我通过手动内存管理搞砸内存的风险。

由于我依赖 shared_ptr 进行对象删除,因此我的代码中没有一个地方可以逻辑地调用 Unsubscribe。

关于在这种情况下该怎么做有什么想法吗?

【问题讨论】:

  • 您遇到了依赖共享指针的问题之一——它们不能替代设计。
  • 它旨在提供帮助。当回答者对问题没有真正了解时,此处显示“使用共享指针”的答案数量。是可怕的。恕我直言,应该始终质疑使用共享指针。如果您这样做了,您可能已经注意到了之前的取消订阅问题。
  • 尼尔,可能更有帮助的是指出设计缺陷可能在哪里,并给出如何修复的想法。我试图在下面的 cmets 中做到这一点。不过,你是对的。默认垃圾收集/依赖析构函数语义可能是设计缺陷的危险信号。
  • 尼尔发表了评论。当然,深入细节会更有帮助,但他不妨将其发布为答案。

标签: c++ shared-ptr observer-pattern subscription weak-ptr


【解决方案1】:
  1. 您可以通过 Subscription 实例销毁对象,然后它会自动删除指针。
  2. 您可以忘记从订阅中删除它们——weak_ptr 无论如何都无法锁定,然后您可以删除它们。
  3. 您可以为每个对象分配一个唯一 ID,然后通过唯一 ID 而不是 shared_ptr 删除
  4. 您可以将普通指针传递给Remove 而不是共享指针——它将用作“ID”。

【讨论】:

  • 1) 对象在使用 TCP/IP 连接到服务器的多个用户之间共享。在我的软件中,让 Subscription 实例成为这些对象的所有者将是一个糟糕的设计选择。 2)问题是如果没有人试图通知这些对象。然后对象将永远存在;导致内存泄漏。 3)是的,这就是我可能会做的。订阅时,客户端会收到一个订阅密钥,他将在取消订阅时使用该密钥。 4)这是我以前做的。不过,我想减少应用程序中 rawa 指针的数量。
  • 1.我的意思是你调用 Subscription->Release(shared_ptr&)。然后它删除weak_ptr 并重置传递的指针。 2. 你可以进行零星的擦除,但这可能会很昂贵——而且只有weak_ptr 会存活,对象本身会死掉。 3. 唯一 ID 有许多其他好处 :) 4. 好点。
  • @Kornel 2. 如果他将它们存储在链表/std::list 中,删除它们的成本不会很高。真正的成本在于每次他将消息传递给订阅者列表时的锁定实现。不过,他已经付出了这个代价。
  • @Martin 让对象订阅/取消订阅本身是许多潜在选择之一,它将对象与订阅机制和/或它订阅的确切对象紧密耦合。该选择使您陷入了允许延迟退订的要求。如果您将连接发布者/订阅者的逻辑推送到其他地方,您可能会在调用它时获得更多控制权,并且能够确保调用它而不依赖于推送给订阅者的每个事件的延迟评估或引用计数行为.对不起所有的recmets。没有编辑功能:)
  • @MerlynMorgan-Graham "如果他将它们存储在链表/std::list 中,删除它们的成本不会很高。" 你的意思是即使清单很长?我不同意。
【解决方案2】:

我的问题是shared_from_this 不能被调用 析构函数,所以上面的代码会抛出异常。

它会抛出一个异常因为它已经过期,根据定义,在析构函数中。

那么你到底想要什么?一个“过期”的共享指针?只需创建一个空的共享指针。

或者过期的弱指针?

也许如果您注意到“问题”不是shared_from_this 抛出(这是一种症状),而是所有所有者在那个时候本质上已经被重置或销毁并且弱指针已过期并且相当于一个空的默认创建的弱指针(*),所以你只需传递一个默认初始化的弱指针。

另外Subscriptions::Instance()->Remove(weak_OR_owning_pointer) 也没有任何意义(无论是弱指针还是拥有指针),因为您无法将弱指针与任何东西进行比较,您只能尝试锁定它(然后进行比较)。

所以你可以删除过期的弱指针。 Remove 的论点没有用。

(*) 要么你有一个非常严重的双重错误,即被销毁的对象的双重所有权!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-24
    • 1970-01-01
    • 1970-01-01
    • 2014-10-13
    • 1970-01-01
    • 2019-04-12
    • 2021-08-28
    • 1970-01-01
    相关资源
    最近更新 更多