C++ 为什么每次成功的QueryInterface()调用后面都跟着Release()调用?

C++ 为什么每次成功的QueryInterface()调用后面都跟着Release()调用?,c++,com,object,interface,queryinterface,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; 有人能解释一下这里调

为什么
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()
的意图吗

为什么QueryInterface调用后面总是跟着Release调用

因为将调用,这将增加指针的引用计数。当指针有0个引用时,它将为您释放

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

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


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

它并不总是像这样直接遵循,尽管这很常见

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


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

此特定代码段似乎只对获取ppv值感兴趣。请注意,释放的不是接口指针。CDecoder类似乎是获取它的工具。这里有一个新的语句来创建它,而不是用标准的COM方法来创建一个COM类,它采用CoCreateInstance()。显然,正确使用该类需要一个Release()调用,而不是使用delete操作符。再说一次,根本不是标准,但也不是不可能。我只能猜测CDecoder是一个C++类,它实现了COM类,这个代码直接使用它,而不是通过正常的COM过程。
不要假定此代码是标准代码。根本不是。

你不能使用
删除
,因为原始接口的QI必须成功,我相信可能必须返回原始指针。正如Jerry解释的那样,接口上的引用计数应该被视为独立的(尽管它们确实合作)。@Ben:接口上没有引用计数,它位于实现接口的对象上。你得到的每个接口都会增加引用数。。。同样在对象上。QueryInterface“may”调用AddRef是一个实现细节。如果QI成功,您有两个对象,当不再使用时,您应该释放这两个对象。@Ismael:您有一个对象实现了示例2个接口。@Brian:错误(您的第一条评论)。您必须
释放
正确的接口指针,否则将断开接口@Ismael:QI的合同是将refcount的所有权转移给调用方。它可以在内部调整引用计数,而不是调用
AddRef
,但它不是一个单独的对象(在两个接口指针上使用QI for IUnknown必须返回相同的值)。但是,它确实有自己的引用计数。这段代码非常罕见。它看起来像是C++细节混淆的COM细节。