为什么每次成功的 QueryInterface() 调用后都会调用 Release() ?
为什么 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()
调用背后的意图吗?
Why is a QueryInterface()
call always followed by a Release()
call? For example, I have seen a sample code from MSDN as below:
HRESULT hr = S_OK;
CDecoder *pObj = new CDecoder(&hr);
if (SUCCEEDED(hr))
{
*ppv = NULL;
hr = pObj->QueryInterface(riid, ppv);
}
pObj->Release();
return hr;
can someone explain the intent behind Release()
call here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
尽管这种情况很常见,但并不总是像这样直接遵循。
COM 对象采用引用计数。当您最初创建该对象时,您将获得一个指向
IUnknown
的指针。然后,您可以使用QueryInterface
获得一些其他接口。由于您(通常)不再关心IUnknown
接口,因此您可以释放它。当你释放你获得的另一个接口时,引用计数将为0,因此该对象可以被销毁。但是,如果不释放IUnknown
,引用计数将保持非零,因此该对象无法被销毁。您不会立即释放
IUnknown
的最明显情况是当/如果您需要获取多个其他接口时。在这种情况下,您将获得IUnknown
,然后在释放IUnknown
之前获得第二个和第三个接口。至少在某些情况下,您在创建对象后可能不知道第三个(或后续)接口,因此您可能需要在任意长度的时间内保留对IUnknown
的访问权限释放它。It's not always followed directly like this, though that is pretty common.
COM objects are reference counted. When you initially create the object, you get a pointer to an
IUnknown
. Then you obtain some other interface withQueryInterface
. Since you (usually) don't care about theIUnknown
interface anymore, you release that. When you release the other interface you obtained, the reference count will be 0 so the object can be destroyed. If you don't release theIUnknown
, however, the reference count will stay non-zero, so the object can't be destroyed.The most obvious case where you would not immediately release the
IUnknown
is when/if you need to get more than one other interface. In such a case, you'd get theIUnknown
, then the second and third interfaces before releasing theIUnknown
. There are at least potentially cases where you might not know the third (or subsequent) interfaces right after you created the object either, so you might need to retain access to theIUnknown
for some arbitrary length of time before releasing it.因为
QueryInterface
将调用AddRef
增加指针的引用计数。当一个指针有 0 个引用时,它就会被释放。注意:这个问题的答案对于 QueryInterface 的实际用途存在一些混淆。它只是检索指向对象上支持的接口的指针,并增加该对象上的引用计数。它不会为它实现的每个接口创建一个新对象。
例如,如果您有一个实现 2 个接口的对象,则调用只需将该对象强制转换为每个接口,并增加一个用作引用计数的变量。
注意:引用计数可以通过不同的方式实现,但上面解释了通常的场景。特别是@Ben 在下面描述了一个撕裂接口,它强调了在返回给您的接口指针上调用 Release 的重要性。
Because
QueryInterface
will callAddRef
which increases the reference count to the pointer. When there are 0 references to a pointer it is freed for you.Note: There is some confusion in this question's answers about what
QueryInterface
actually does. It simply retrieves pointers to the supported interfaces on an object and increments the reference count on that object. It doesn't create a new object for each interface that it implements.For example if you have an object which implements 2 interfaces, then the call would simply cast that object as each of the interface and increment a variable which is used as the reference count.
Note: The reference counting can be implemented in different ways, but the above explains the usual scenario. In particular @Ben describes a tear off interface below which stresses the importance of calling Release on the interface pointer that was returned to you.
这个特定的代码片段似乎只对获取ppv值感兴趣。请注意,接口指针没有被释放。 CDecoder 类似乎是获取它的工具。有一个 new 语句来创建它,而不是使用 CoCreateInstance() 的标准 COM 方法来创建 COM 类。显然,正确使用该类需要调用 Release() 而不是使用删除运算符。同样,这根本不标准,但并非不可能。我只能猜测 CDecoder 是一个实现 COM coclass 的 C++ 类,并且此代码直接使用它,而不是通过正常的 COM 过程。
不要假设此代码是标准的。根本不是。
This particular code snippet appears to only be interested in obtaining the ppv value. Note that it is not that interface pointer being released. The CDecoder class appears to be the vehicle to get it. There a new statement to create it, not otherwise the standard COM way to create a COM class, that takes CoCreateInstance(). Apparently proper usage of that class requires a Release() call instead of using the delete operator. Again, not standard at all but not impossible. I can only guess that CDecoder is a C++ class that implements a COM coclass and this code is using it directly rather than going through the normal COM procedures.
Don't assume this code is standard. It is not at all.