为什么每次成功的 QueryInterface() 调用后都会调用 Release() ?

发布于 2024-10-18 06:38:02 字数 350 浏览 1 评论 0原文

为什么 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

却一份温柔 2024-10-25 06:38:02

尽管这种情况很常见,但并不总是像这样直接遵循。

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 with QueryInterface. Since you (usually) don't care about the IUnknown 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 the IUnknown, 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 the IUnknown, then the second and third interfaces before releasing the IUnknown. 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 the IUnknown for some arbitrary length of time before releasing it.

我很OK 2024-10-25 06:38:02

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

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

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

例如,如果您有一个实现 2 个接口的对象,则调用只需将该对象强制转换为每个接口,并增加一个用作引用计数的变量。

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

Why is a QueryInterface call is always followed by a Release call?

Because QueryInterface will call AddRef 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.

森林迷了鹿 2024-10-25 06:38:02

这个特定的代码片段似乎只对获取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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文