inline void intrusive_ptr_add_ref(IUnknown* ptr) { ptr->AddRef(); } inline void intrusive_ptr_release(IUnknown* ptr) { ptr->Release(); }
With these defined, intrusive_ptr will play nice with COM objects. However, getting them into the intrusive_ptr is a little trickier. The standard technique for COM functions is to take as a parameter a pointer-to-pointer, which, if the operation is successful, will be assigned to the address of the object being created or acquired. Also, incrementing the object's reference count is handled by the callee, not the caller. This behavior is the opposite of what intrusive_ptr expects. Both problems can be solved via a small helper class and function:
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); }
The WrapPtr class acts as a proxy for the intrusive_ptr object when calling COM functions. It is designed to be used in the following manner:
D3D11_TEXTURE3D_DESC desc; boost::intrusive_ptr<ID3D11Texture3D> texture; HRESULT hr = m_d3dDevice->CreateTexture3D(&desc, NULL, AttachPtr(texture));
Using intrusive_ptr for RAII vastly reduces the verbosity involved in interfacing with COM objects, and makes it much easier to write exception safe code.
No comments:
Post a Comment