释放COM接口的正确方法

释放COM接口的正确方法,com,c++-winrt,Com,C++ Winrt,我们有一些使用COM的遗留软件代码。我注意到,在一个地方,我们对IInspectable指针执行queryInterface,但不用麻烦调用release 例如: void foo(IInspectable* myInterface) { ComPtr<OBJTYPE> pObj; auto hr = myInterface->QueryInterface(__uuidof(SomeType),&pObj); if (hr != S_OK)

我们有一些使用COM的遗留软件代码。我注意到,在一个地方,我们对IInspectable指针执行queryInterface,但不用麻烦调用release

例如:

void foo(IInspectable* myInterface)
{
    ComPtr<OBJTYPE> pObj;
    auto hr = myInterface->QueryInterface(__uuidof(SomeType),&pObj);
    if (hr != S_OK)
    {
        return hr;
    }
    //some code that uses pObj
}
void foo(IInspectable*myInterface)
{
ComPtr pObj;
auto hr=myInterface->QueryInterface(uuuidof(SomeType),&pObj);
如果(hr!=S_正常)
{
返回人力资源;
}
//一些使用pObj的代码
}
我在上述代码中添加了以下版本:

auto hr = myInterface->QueryInterface(__uuidof(SomeType),&pObj);
if (hr != S_OK)
{
    return hr;
}
myInterface->Release(); //<-- Is this the correct way to release ?
//some code that uses pObj;
auto hr=myInterface->QueryInterface(uuu-uuidof(SomeType),&pObj);
如果(hr!=S_正常)
{
返回人力资源;
}

myInterface->Release()// 在第一个
foo
函数中,不应调用
myInterface->Release()。每次调用
Release
都应该添加一个引用。在该函数中,您不需要执行
myInterface->AddRef
,因此如果您添加
myInterface->Release
,那么您的函数会将引用计数减少1,这似乎不是正确的行为

从概念上讲,您应该在进入函数时调用
AddRef
,在退出函数时调用
Release
。即使引用计数在COM中是“侵入式”的,建议的编码风格是将每个接口指针视为具有自己的引用计数

这通常包含在智能指针类中。但是,当使用接收原始“in”接口指针的函数时,可以通过省略函数中的这两个调用并将指针视为观察者指针来“优化”此添加和释放



调用
QueryInterface
将隐式执行
pObj->AddRef()
,但这与
myInterface
无关。当您完成
pObj
a
pObj->Release()
时,应该会发生,但这是由
ComPtr
包装器管理的,您不应该添加显式调用。

似乎是WRL的一部分,而不是C++/WinRT。
ComPtr
析构函数将为您调用
Release
。显式调用它将导致双重删除错误。由于您将
myInterface
作为普通指针传递,这意味着接口上没有所有权转移;这是一个非所有者指针。您只负责
OBJTYPE
接口,而
ComPtr
为您负责。
Microsoft::WRL::ComPtr
是一个COM智能指针,与ATL的
CComPtr
非常相似。您不需要显式地调用
Release
,因为智能指针会为您这样做。看见C++/WinRT有一个类似的
WinRT::com_ptr
可以用来代替WRL。“但这与
myInterface
”有点牵强。在绝大多数情况下,对
QueryInterface
的调用将返回一个指针,指向与被调用方相同的对象实现的接口。我相信撕下的接口是唯一的例外。引用计数是按对象进行的,而不是按接口进行的。@IInspectable请看我的第二段。我并不反对这一点,只是最后一段偏离了概念思维,并做出了一个通常是错误的陈述。我不确定那一段是应该改写,还是完全删除。它没有像写的那样增加多少价值。