I’ve read an article about using boost::intrusive_ptr for managing COM objects. The author shows a wrapper class which takes care of adjusting the smart pointer for the usual COM semantics. This is the class:
template <typename T>
class WrapPtr
{
public:
WrapPtr(boost::intrusive_ptr<T>& ref)
: m_ref(ref), m_ptr(0)
{
}
~WrapPtr()
{
// The second parameter indicates that the reference count should not be incremented
m_ref = boost::intrusive_ptr(m_ptr, false);
}
operator T**()
{
return &m_ptr;
}
operator void**()
{
// Some COM functions ask for a pointer to void pointer, such as QueryInterface
return reinterpret_cast<void**>(&m_ptr);
}
private:
T* m_ptr;
boost::intrusive_ptr<T> m_ref;
};
template <typename T>
WrapPtr<T> AttachPtr(boost::intrusive_ptr<T>& ref)
{
return WrapPtr<T>(ref);
}
What I don’t understand is the destructor. It will discard the current m_ref object (which will lead to a call to Release of course), but then he assigns a new intrusive_ptr constructed from the m_ptr member. I don’t understand why this is needed in the destructor, since the Wrapper class is holding a copy of the intrusive_ptr, not a reference to it. If the callee changed the pointed object, this change will be lost after the destructor is left. Is this a bug here or am I missing something?
In a similar “safe address-of” class I once saw, the class had an intrusive_ptr reference (
intrusive_ptr<T>&), not an actual object (intrusive_ptr<T>). The class you posted won’t actually affect the client’s intrusive_ptr. So it looks like the code is just buggy: it should hold a reference to the client’s intrusive_ptr, not a separate intrusive_ptr object:EDIT: I forgot to answer your actual question 🙂
With the fix above, what the destructor does becomes clearer: it sets the client’s intrusive_ptr to hold the pointer that was set by calling operator T** or operator void** and passing it to a “getter” method (e.g. QueryInterface).