CBasePin 递增对拥有过滤器的引用。循环引用?

CBasePin incrementing reference to owning filter. Circular reference?

我终于鼓起勇气第一次尝试构建一个DirectShow过滤器。这可能是一个愚蠢的问题,但我很困惑。

我的过滤器源自 CBaseFilter,并拥有一个源自 CBaseInputPin 的输出引脚。输出引脚的成员引用由 CComPtr 智能指针持有。构造输出引脚时,我注意到它在哑指针上存储了对 "owner" 过滤器的引用。对我来说很有意义,因为我们不想创建循环引用。

但是,当CComPtr成员添加对输入引脚的引用时,会调用CBasePin::NonDelegatingAddRef()方法。

这是方法的源代码

/* Override to increment the owning filter's reference count */

    STDMETHODIMP_(ULONG)
    CBasePin::NonDelegatingAddRef()
    {
        ASSERT(InterlockedIncrement(&m_cRef) > 0);
        return m_pFilter->AddRef();
    }

我想不通为什么子 pin 需要增加拥有过滤器的引用计数(实际上创建循环引用)。

我是否应该将拥有的 pin 的引用保存在一个哑指针上并删除它而不考虑引用计数?

过滤器和引脚是 COM 对象,但它们没有单独的生命周期。他们只有一个引用计数——过滤器。引脚引用和取消引用有效地递增和递减过滤器的计数器,当它达到零过滤器时,它的所有引脚都被销毁。

外部代码以通常的方式处理 COM 指针。在内部,许多过滤器示例向您展示了方法,完成后删除引脚,例如(random pick):

//
// CSource::Destructor
//

CSource::~CSource()
{
    /*  Free our pins and pin array */
    while (m_iPins != 0) {
    // deleting the pins causes them to be removed from the array...
        delete m_paStreams[m_iPins - 1];
    }
    ASSERT(m_paStreams == NULL);
}

在大多数情况下,引脚是静态的,并在过滤器的析构函数中被删除。当它们是动态的时,随时删除它们是不安全的,因为它们的接口指针可能会在您要删除的对象上保持挂起 IUnknown::Release 的引用。但是,如果您只是将其保留在过滤器内部的侧列表中以在过滤器销毁时推迟删除,这将是安全的。

此外,您不应该在过滤器中使用 CComPtr 管理的引脚。预期的方式显示在同一段代码中:newdelete 用于 pin 对象,并将原始指针直接指向过滤器代码中的 pin。外部代码通过其 COM 接口指针与引脚通信。