将 DirectX 接口强制转换为 IUnknown 指针

Cast DirectX interfaces to IUnknown pointers

本文关键字:IUnknown 指针 转换 DirectX 接口      更新时间:2023-10-16

我的代码中有相当多的接口,我想将重复Release代码封装在另一个方法中而不是宏中,因为这很C++,而且我讨厌使用宏。我最初的尝试是编写一个方法,

例如
void SafeRelease(IUnknown **ppInterface) {
    if(*ppInterface) {
        (*ppInterface)->Release();
        (*ppInterface) = nullptr;
    }
}

但是,将此方法应用于IDirect3DSurface9 *例如SafeRelease(&mySurface)会产生错误IDirect3DSurface9 **IUnknown **不兼容。

  1. 我在这里做错了什么?
  2. 有没有更好的方法(希望不使用宏(来实现这样的功能?
这是我

的方法:

template <typename T> void SafeRelease(T*& ptr)
{
    if(ptr)
    {
        ptr->Release();
        ptr = nullptr;
    }
}

用法示例:

IDirect3DDevice9 *pD3DDevice = NULL;
d3d->CreateDevice(..., &pD3DDevice);
SafeRelease(pD3DDevice);

如果需要,您可以inline此功能。

您可以使用模板:

template<class DXInterface>
void SafeRelease(DXInterface **ppInterface) {
    if(*ppInterface) {
        (*ppInterface)->Release();
        (*ppInterface) = nullptr;
    }
}
您还可以使用 std::

unique_ptr 或 std::shared_ptr 来自动清理:

#include <memory>
#include <iostream>
struct Releaser {
   template<class DXInterface>
   void operator()(DXInterface *pInterface) const {
       if(pInterface) {
           pInterface->Release();
       }
   }
};
// For illustrative purposes only (supplied in DX9 headers)
struct IDirect3DSurface9 { void Release() { std::cout << "Released surfacen";} };
struct IDirect3DTexture9 { void Release() { std::cout << "Released texturen";} };
void DX9CreateSurface( IDirect3DSurface9** surface ) 
{ 
    *surface = new IDirect3DSurface9();
}
void DX9CreateTexture( IDirect3DTexture9** texture ) 
{ 
    *texture = new IDirect3DTexture9();
}
// Your factory functions
IDirect3DSurface9* createSurface( /*init params go here*/ )
{
    IDirect3DSurface9* surface;
    DX9CreateSurface( &surface );
    return surface;
}
IDirect3DTexture9* createTexture( /*init params go here*/ )
{
    IDirect3DTexture9* texture;
    DX9CreateTexture( &texture );
    return texture;
}
int main()
{
  typedef std::unique_ptr<IDirect3DSurface9, Releaser> SurfacePtr;
  typedef std::unique_ptr<IDirect3DTexture9, Releaser> TexturePtr;
  SurfacePtr surface( createSurface() );
  TexturePtr texture( createTexture() );
  // ... use surface and texture here
  // Automatically released here when their lifetimes ends.
}

请注意,它们使用相同的 Releaser,并注意对 surface.reset(( 的调用也会释放接口,并将unique_ptr内的指针设置为 null 以启动。这两个对象可以是类的成员,而不是 main(( 中的对象。

我在这里做错了什么?

我刚刚有同样的问题,也适用于 COM SafeRelease.所以这里是:

void SafeRelease(IUnknown **ppInterface) 
...
IDirect3DSurface9 * mySurface = new ...
...
SafeRelease(&mySurface);

IDirect3DSurface9 *,凭借继承,可以铸造到IUnknown *。但是,与直觉相反,IDirect3DSurface9 **不能投射到IUnknown **.如果允许,那么在您的SafeRelease(IUnknown**)内,您可以执行以下操作:

// obtain a pointer to an instance of some random subinterface of IUnknown
*ppInterface = pMyRamdomComInterfacePointer;
因此,我们将在指向

IDirect3DSurface9的指针中存储指向某些随机IUnknown导数的指针。这将违反C++类型系统。这就是为什么不允许将除T**转换为T**以外的任何其他类型的转换。换句话说,T** 类型的变量只能分配一个ppT(类型 T** 的值(,而不能分配一个ppSomeSubytpeOfT

比较一下:为什么指向派生类的指针不能传递给期望引用指向基类的指针的函数?这个:强制转换基类的双指针。

对于 COM SafeRelease ,模板(如此处建议(或宏都可以。