为什么每个成功的QueryInterface()调用后跟Release()调用?

时间:2011-02-18 23:36:14

标签: c++ com object interface queryinterface

为什么QueryInterface()来电始终跟Release()来电?例如,我在MSDN中看到了一个示例代码,如下所示:

HRESULT hr = S_OK;
CDecoder *pObj = new CDecoder(&hr);

if (SUCCEEDED(hr))
{
    *ppv = NULL;
    hr = pObj->QueryInterface(riid, ppv);
}
pObj->Release();
return hr;

有人可以在这里解释Release()电话背后的意图吗?

3 个答案:

答案 0 :(得分:15)

这并不总是像这样直接跟随,虽然这很常见。

COM对象被引用计数。最初创建对象时,会得到指向IUnknown的指针。然后,您获得了QueryInterface的其他一些界面。由于您(通常)不再关心IUnknown接口,因此您将释放它。当您释放您获得的其他接口时,引用计数将为0,因此可以销毁该对象。但是,如果不释放IUnknown,则引用计数将保持非零,因此无法销毁该对象。

立即释放IUnknown的最明显的情况是/当您需要获得多个其他界面时。在这种情况下,在发布IUnknown之前,您将获得IUnknown,然后是第二和第三个接口。至少在某些情况下,您可能在创建对象后立即不知道第三个(或后续)接口,因此您可能需要在释放之前保留对IUnknown的访问权限一段任意长度。

答案 1 :(得分:8)

  

为什么QueryInterface调用总是后跟Release调用?

因为QueryInterface会调用AddRef,这会增加指针的引用次数。当对指针有0个引用时,它就会被释放。

注意:关于QueryInterface实际做了什么,这个问题的答案存在一些混淆。它只是检索指向对象上支持的接口的指针,并增加该对象的引用计数。它不会为它实现的每个接口创建一个新对象。

例如,如果你有一个实现2个接口的对象,那么调用只会将该对象转换为每个接口,并增加一个用作引用计数的变量。

注意:引用计数可以以不同的方式实现,但上面解释了通常的情况。特别是@Ben描述了一个撕下接口,下面强调了在返回给你的接口指针上调用Release的重要性。

答案 2 :(得分:4)

此特定代码段似乎只对获取 ppv 值感兴趣。请注意,正在释放的接口指针 not 。 CDecoder类似乎是获得它的工具。有一个 new 语句来创建它,而不是创建COM类的标准COM方法,它采用CoCreateInstance()。显然,正确使用该类需要调用Release()而不是使用 delete 运算符。同样,根本不是标准,但并非不可能。我只能猜测CDecoder是一个实现COM coclass的C ++类,这段代码直接使用它而不是通过正常的COM程序。

不要认为此代码是标准的。它完全没有。