COM引用计数 - 依赖于对象的对象

时间:2014-10-22 15:42:14

标签: com atl refcounting

我有两个COM对象(让我们称之为ControlJob)。控制是CoCreatable,Job对象由Control.NewJob()创建。

Control有一个方法Control.Start(job),它使指定的作业成为当前作业。只要没有设定其他工作,它仍然是当前的工作。

现在,对于客户端,以下行为对于这些特定控件似乎是合理的:

  • 只要其中一个作业存在,控制就存在了 (琐碎:Job对其创建的Control有很强的参考作用)

  • 只要客户端具有对Control或其CurrentJob的引用,就不会被销毁 ("琐碎的":CurrentJob是一个强大的参考)

  • 客户不需要"清除"发布参考文献之前的CurrentJob

现在,我在这里有一个经典的循环引用,释放它的条件是两个对象没有外部引用。

可以通过解决ATL的InternalRelease实现来解决这个问题,但这非常丑陋和孤立。

有什么建议吗?现有方案?

2 个答案:

答案 0 :(得分:2)

  

只要其中一个作业存在,控制存在

不,相当确定这是你出错的规则。密切关注球,你添加IControl :: CreateJob()工厂函数的唯一原因是给CJob(实现类,而不是接口)一个CControl *引用。这意味着所有权,特定的IJob只能与特定的Control实例相关联。因此,CControl应保留其拥有的CJobs集合。

现在变得直截了当:

  • CControl实例正常创建,只有一个 AddRef()调用,只有应用程序拥有该实例。
  • IControl :: CreateJob()实现方法使用CJob(Control *)构造函数创建一个新的CJob,将其添加到集合并返回IJob接口指针。只有一个 AddRef()调用,只有客户端应用程序拥有该实例。
  • CJob析构函数调用私有CControl :: RemoveJob()方法,使用从构造函数中获取的CControl *(如果它不为空)从集合中删除它。
  • CControl析构函数迭代其集合,设置CControl *,任何剩余的CJob维持回null。他们现在是非拥有的。
  • IControl :: Start(IJob *)实现方法调用AddRef()以确保作业保持活动状态。作业完成或被替换或CControl对象被销毁时释放。请注意,需要进行错误检查,该方法需要迭代集合以查找匹配的CJob对象。因此,客户端无法启动由另一个Control实例创建的作​​业。并允许您将CJob *保留为CControl :: currentJob私有变量。

答案 1 :(得分:1)

我不认为ATL有开箱即用的解决方案,因为有问题的行为对特定要求很敏感。

  

只要客户端有对Control或其CurrentJob的引用,它们都不会被销毁("琐碎":CurrentJob是一个强大的参考)

此要求假定从当前作业的一侧存在对Control的外部强引用,因为控件需要保持活动状态,仅客户端到作业引用。也就是说,控制和工作都有很强的参考。然后控制+作业组合需要正确处理所有外部引用的释放。例如,这可以通过以下方式实现。

作业(和控制器的相同方式?)CComObjectRootEx::InternalRelease被覆盖,它会检查唯一的外部引用是否仍然是控件的外部引用。如果是这种情况,则作业正在启动终止检查 - 它调用某些控件的方法来检查其引用。如果作业的引用是唯一的引用控件,那么它们都会释放引用到另一个(并终止)。