QueryInterface()可以在成功时为我们提供nullptr吗?

时间:2014-08-15 11:49:21

标签: c++ com hresult nullptr queryinterface

想象一下情况:

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是一个冗余部分。我是对的吗?

1 个答案:

答案 0 :(得分:1)

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()。两者都可能被破坏,并且您的里程可能会随着检查指针被检查为空而有所不同。