我有两个COM对象(让我们称之为Control
和Job
)。控制是CoCreatable,Job对象由Control.NewJob()
创建。
Control有一个方法Control.Start(job)
,它使指定的作业成为当前作业。只要没有设定其他工作,它仍然是当前的工作。
现在,对于客户端,以下行为对于这些特定控件似乎是合理的:
只要其中一个作业存在,控制就存在了 (琐碎:Job对其创建的Control有很强的参考作用)
只要客户端具有对Control或其CurrentJob的引用,就不会被销毁 ("琐碎的":CurrentJob是一个强大的参考)
客户不需要"清除"发布参考文献之前的CurrentJob
现在,我在这里有一个经典的循环引用,释放它的条件是两个对象没有外部引用。
我可以通过解决ATL的InternalRelease实现来解决这个问题,但这非常丑陋和孤立。
有什么建议吗?现有方案?
答案 0 :(得分:2)
只要其中一个作业存在,控制存在
不,相当确定这是你出错的规则。密切关注球,你添加IControl :: CreateJob()工厂函数的唯一原因是给CJob(实现类,而不是接口)一个CControl *引用。这意味着所有权,特定的IJob只能与特定的Control实例相关联。因此,CControl应保留其拥有的CJobs集合。
现在变得直截了当:
答案 1 :(得分:1)
我不认为ATL有开箱即用的解决方案,因为有问题的行为对特定要求很敏感。
只要客户端有对Control或其CurrentJob的引用,它们都不会被销毁("琐碎":CurrentJob是一个强大的参考)
此要求假定从当前作业的一侧存在对Control的外部强引用,因为控件需要保持活动状态,仅客户端到作业引用。也就是说,控制和工作都有很强的参考。然后控制+作业组合需要正确处理所有外部引用的释放。例如,这可以通过以下方式实现。
作业(和控制器的相同方式?)CComObjectRootEx::InternalRelease
被覆盖,它会检查唯一的外部引用是否仍然是控件的外部引用。如果是这种情况,则作业正在启动终止检查 - 它调用某些控件的方法来检查其引用。如果作业的引用是唯一的引用控件,那么它们都会释放引用到另一个(并终止)。