Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is every successful QueryInterface() call followed by Release() call?

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?

like image 678
Arun Reddy Kandoor Avatar asked Feb 18 '11 23:02

Arun Reddy Kandoor


2 Answers

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.

like image 62
Jerry Coffin Avatar answered Oct 19 '22 21:10

Jerry Coffin


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.

like image 8
Brian R. Bondy Avatar answered Oct 19 '22 20:10

Brian R. Bondy