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细节。