If we can have std::atomic<std::shared_ptr>, why not std::atomic<com_ptr>?

Controlling the reference count. The post If we can have std::atomic, why not std::atomic? appeared first on The Old New Thing.

Apr 29, 2025 - 20:10
 0
If we can have std::atomic<std::shared_ptr>, why not std::atomic<com_ptr>?

Some time ago, we peeked inside the atomic shared_ptr to see how it worked. Can we apply these same principles to create an atomic com_ptr?

Recall that the atomic shared_ptr operates by using the bottom bit of the control block pointer as a lock flag, so that nobody can change the value while we’re copying the pointer and incrementing the reference count. Can we do this with a com_ptr?

We could use the same trick of using the bottom bit of the raw COM pointer as a lock flag. This is acceptable because COM pointers must be pointer-aligned (since they point to a vtable), so we know that the bottom bit of a valid COM pointer is clear. However, we run into trouble when trying to increment the reference count: The call to IUnknown::AddRef happens while the lock is held, but the AddRef is a call out to external code, and we don’t know what it’s going to do. We know what it’s supposed to do (namely, increment the reference count), but it may take a circuitous route to get there, including passing through aggregated controlling unknowns, tear-off stubs, tear-offs of aggregated objects, weak outer pointers, and other fanciful characters.

We know that holding a lock while calling out to external code is a source of deadlocks, so holding a lock while calling out to a mystery implementation of IUnknown::AddRef is probably not a good idea.

Sorry.

The post If we can have std::atomic, why not std::atomic? appeared first on The Old New Thing.