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

Aru*_*oor 11 c++ com interface object 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;
Run Code Online (Sandbox Code Playgroud)

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

Jer*_*fin 15

它并不总是像这样直接跟随,尽管这很常见.

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

不会立即释放的最明显的情况IUnknown是何时/如果您需要获得多个其他接口.在这种情况下,你会IUnknown在释放之前得到第二个和第三个接口IUnknown.至少有可能在您创建对象之后可能不知道第三个(或后续)接口的情况,因此您可能需要IUnknown在释放之前保留对该任意长度的访问权限.


Bri*_*ndy 8

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

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

注意:这个问题的答案QueryInterface实际上有些混乱.它只是检索指向对象上支持的接口的指针,并增加该对象的引用计数.它不会为它实现的每个接口创建新对象.

例如,如果您有一个实现2个接口的对象,那么该调用将简单地将该对象强制转换为每个接口,并递增一个用作引用计数的变量.

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