想象一个场景:
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,您的里程都可能发生变化。