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

12.1k views Asked by At

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?

3

There are 3 answers

10
Brian R. Bondy On

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.

0
Jerry Coffin On

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.

1
Hans Passant On

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.