2013-02-04 48 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,無論是模板(如建議在這裏)或宏會做。