首页 > 解决方案 > CBasePin 递增对拥有过滤器的引用。循环引用?

问题描述

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

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

但是,当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();
    }

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

我是否应该将拥有的引脚的引用保存在哑指针上并不管引用计数如何都将其删除?

标签: c++comdirectshow

解决方案


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

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

//
// 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在过滤器内部管理引脚。预期的方式显示在同一段代码中:对于 pin 对象和过滤器代码中指向 pin 的直接原始指针newdelete外部代码通过其 COM 接口指针与引脚通信。


推荐阅读