QueryInterface()成功时是否可以提供nullptr ?

Could QueryInterface() provide us with nullptr when succeed?

本文关键字:nullptr 是否 成功 QueryInterface      更新时间:2023-10-16

想象一个场景:

CComPtr<IGraphBuilder> pGraph;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
if (SUCCEEDED(hr))
{
    CComPtr<IMediaControl> pControl;
    hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
    if(SUCCEEDED(hr))
    {...}
}

我想知道,pControl是否可以在最后一个块{...}中成为nullptr。问题出现了,因为我看到了这段代码:

if(SUCCEEDED(hr) && pControl)
{...}

我认为&& pControl部分是多余的。我说的对吗?

QueryInterface() 需要在成功失败时提供一个有效的(因此非空)接口指针。但是,您不知道某些特定的实现是否遵循该规则,并且您引用的代码很可能试图进行防御。

也就是说,下面的

HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
    CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));

还在底层调用QueryInterface()来检索指向所请求接口的指针。如果代码想要防御,它也应该检查pGraph在成功时是否为非空。

这里的问题是,当你得到S_OK和一个空指针时,你不知道它有多糟糕。假设QueryInterface()是这样工作的(后面是非常糟糕的代码,不适合在的任何地方使用):

HRESULT TheClass::QueryInterface( REFIID iid, void** ppv )
{
    if( iid == SomeSpecificIID ) {
        AddRef();
        *ppv = 0; //BAD IDEA, BAD CODE, JUST DON'T
        return S_OK;
    } else {
       //whatever
    }
}

很好,防御代码将避免解引用这里检索到的空指针和返回的S_OK,但引用计数将是不正确的-没有人将有机会调用匹配的Release()。因此,您实例化这样一个对象,然后调用QueryInterface(),其工作原理如上所述,refcount现在是2,然后您Release()对象一次,它泄漏。结果到底有多糟取决于很多因素。

CoCreateInstance()相同-它在引擎盖下调用相同的QueryInterface()。两者都可能被破坏,并且无论是否检查检索到的指针是否为null,您的里程都可能发生变化。