想象一下情况:
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
是一个冗余部分。我是对的吗?
答案 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()
。两者都可能被破坏,并且您的里程可能会随着检查指针被检查为空而有所不同。