From examples I've seen COM IUnknown::Release()
function implementation is something like that:
ULONG Release()
{
InterlockedDecrement(&m_count);
if(m_count == 0) {
delete this;
}
return m_count;
}
So, if m_count is 0, so we're deleting "this" object, and returning the ref count.
What I don't understand is why it works ?!?!
Deleting the object wouldn't ruin the call stack or is it okay because it is being held by the thread, so it has nothing to do with the object ???
If the object has been deleted, how is it possible that we can return m_count, it should've been deleted. I could have convinced myself that it's okay if after the delete the code would return hard-coded 0, but how come it can return the member ?!?!
Thanks a lot for your help! :-)
That code is bogus. One can never trust m_count after the decrement. The correct code is always like this:
ULONG Release()
{
ULONG count = InterlockedDecrement(&m_count);
if(count == 0){ delete this; }
return count;
}
What you observe is undefined behavior. The call stack is not changed by delete this;
and delete this
by itself is always safe but renders this
pointer invalid which means you can't dereference it anymore.
There're two possible explanations of what you observe. Either the implementation in question just doesn't dereference this
pointer to obtain m_count
when returning from the function - it has it loaded onto a register and just uses that value and so this
is not dereferenced and you don't observe any problem or when delete
finishes the memory occupied by the object is still mapped into the process address space and remains technically accessible and so dereferencing this
succeeds and m_count
is read successfully. I suppose the latter is more likely.
Whatever the explanation is that undefined behavior, you can't rely on that, use what user Remus Rusanu suggests in his answer.