0

In my application I need to defer releasing of COM interfaces until a later point. Therefor, I'm storing the interface pointers in std::vector<IUnknown*> COMInterfaces and later I loop through all the pointers and call Release() like so:

for(IUnknown* item : COMInterfaces) item->Release();

In the following link, in section 4.1.3, however, I read:

In COM, only interfaces are reference counted, not the objects themselves. After a client has obtained a reference to a particular interface, it must call the release method on exactly that interface, and not a different interface referring to the same object.

So, now I'm a bit confused whether it's ok to release interfaces polymorphically or not. I can't find any documentation that clearly states if this is ok or not.

Edit: Comments below confirm that this works and I'm going to use it like this. However, any pointers to an official documentation would be welcome as well as any explanation on why sometimes I see the following code (this is also how SafeRelease() is defined by Microsoft)

template<class T>
void Release(T*& comInterface) {
    if(comInterface) {
      comInterface->Release();
      comInterface = nullptr;
    }
}

instead of

void Release(IUnknown*& comInterface) {
    if(comInterface) {
      comInterface->Release();
      comInterface = nullptr;
    }
}
rashmatash
  • 1,699
  • 13
  • 23
  • 2
    What you cannot do is cast an IUnknown* into anything else (you must always use QueryInterface, not "raw" casting). If you don't do this, there shouldn't be any problem. – Simon Mourier May 13 '21 at 16:42
  • 1
    Any COM interface is an IUnknown. Any cast down or cast up as long as you only call `AddRef()`, `Release()`, and `QueryInterface()` should be safe. Say you have an `IDispatch` interface. You call `lpDisp->Release()`. It would give same result if you called `((IUnknown*) lpDisp)->Release()`. – Joseph Willcoxson May 13 '21 at 17:05
  • 1
    I believe this paragraph specifically means interfaces that can only be found with `QueryInterface` (and not by downcasting). At that point, diamond inheritance comes into play and each queryable interface has its own copy of `IUnknown`. These copies can have different implementations of the three methods, which is probably what this paragraph warns about – IWonderWhatThisAPIDoes May 13 '21 at 17:09
  • On a side note, it would be safer to use `std::vector>` instead, then you don't have to call `Release()` manually. This way, the interfaces are released automatically when the `vector` goes out of scope, especially if an unexpected exception is thrown. – Remy Lebeau May 13 '21 at 17:33
  • Your version of `Release` can't be called with any pointer type other than `IUnknown*` specifically. This is unrelated to COM, just basic type safety. If you could pass `Dervied* p` to a function taking `Base*&`, that function could assign some unrelated `AnotherDerived*` to `p`. – Igor Tandetnik May 15 '21 at 02:46

0 Answers0