【问题标题】:Why is every successful QueryInterface() call followed by Release() call?为什么每次成功的 QueryInterface() 调用后跟 Release() 调用?
【发布时间】:2011-06-30 04:20:22
【问题描述】:

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

【问题讨论】:

  • 那个代码很不寻常。这看起来像是对 COM 细节的 C++ 混淆。

标签: c++ com object interface queryinterface


【解决方案1】:

虽然这很常见,但并不总是像这样直接遵循。

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 正如 Jerry 解释的那样,接口上的引用计数应该被视为独立的(尽管它们确实合作)。
    • @Ben:接口上没有引用计数之类的东西,它在实现接口的对象上。你得到的每个接口都会增加引用计数……再次在对象上。
    • QueryInterface“可能”调用 AddRef 是一个实现细节。发生的情况是,如果 QI 成功,您有两个对象,并且您应该在不再使用时释放它们。
    • @Ismael:您有 1 个对象实现了例如 2 个接口。
    • @Brian:错误(对于您的第一条评论)。你必须Release正确的接口指针,否则撕掉接口中断。 @Ismael:QI 的合同是将引用计数的所有权转移给调用者。它可以在内部调整引用计数而不是调用AddRef,但它不是一个单独的对象(在两个接口指针上使用 QI 表示 IUnknown 必须返回相同的值)。但是,它确实有自己的引用计数。
    【解决方案3】:

    这个特定的代码 sn-p 似乎只对获取 ppv 值感兴趣。请注意,释放接口指针的不是。 CDecoder 类似乎是获得它的工具。有一个 new 语句来创建它,而不是创建 COM 类的标准 COM 方法,它采用 CoCreateInstance()。显然,该类的正确使用需要 Release() 调用而不是使用 delete 运算符。同样,一点也不标准,但并非不可能。我只能猜测 CDecoder 是一个实现 COM coclass 的 C++ 类,而这段代码直接使用它,而不是通过普通的 COM 过程。

    不要假设此代码是标准的。根本不是。

    【讨论】:

    • 你不能使用delete,因为原始接口的QI必须成功,我相信可能必须返回原始指针。
    猜你喜欢
    • 2021-09-18
    • 2017-12-10
    • 2014-09-26
    • 1970-01-01
    • 2019-11-23
    • 2018-06-13
    • 1970-01-01
    • 2020-05-10
    相关资源
    最近更新 更多