2013-02-04 51 views
1

有相当多的接口在我的代码,我想封装在另一种方法,而不是在宏重复Release代码,因为这是C++,我讨厌使用宏。我的最初尝试是写的方法如演员的DirectX接口的IUnknown指针

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

但是将这种方法应用于一个IDirect3DSurface9 *例如如SafeRelease(&mySurface)产生错误IDirect3DSurface9 **IUnknown **不兼容。

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

是否有创建这样一个函数的原因,而不是使用'ComPtr'? – Duncan

回答

1

这里是我的方法:

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

用法示例:

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

您可能inline如果你想要这个功能。

+0

+1。使用'*&'的模板比我最初的尝试和金属建议更方便! –

0

你可以使用一个模板:

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 surface\n";} }; 
struct IDirect3DTexture9 { void Release() { std::cout << "Released texture\n";} }; 

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. 
} 

注意,他们使用相同的释放器,并注意到对surface.reset()的调用也会释放该接口,并将unique_ptr中的指针设置为null以引导。这两个对象可以是你的类的成员,而不是main()中的对象。

+0

这样我就必须为所有我正在使用的Direct3D接口以及需要发布的Direct3D接口定义这种方法。这就是我为什么要使用'IUnknown'的原因。 –

+1

更好地使Releaser的operator()成为一个模板。 – Puppy

+0

从技术上讲,编译器会为您定义它们,无论您是否将其作为模板,它都几乎肯定会内联该函数。另请参阅我关于使用智能指针的更新。 – metal

0

我在做什么在这里错了吗?

我只是有同样的问题,也为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; 

这样,我们会保存一个指向一些随机IUnknown衍生物指针IDirect3DSurface9。这会违反C++类型的系统。这就是为什么铸造任何其他类型,但T**T**是不允许的。换句话说,T**类型的变量只能分配一个ppT,而不是一个ppSomeSubytpeOfT(一种T**的值)。

比较这一个:How come a pointer to a derived class cannot be passed to a function expecting a reference to a pointer to the base class?这一个:Casting double pointers of base classes

对于COM SafeRelease,无论是模板(如建议在这里)或宏会做。