1

私のコードにはかなりの数のインターフェイスがあり、繰り返しコードをマクロではなく別のメソッドにカプセル化したかったReleaseのです。これは C++ であり、マクロの使用が嫌いだからです。私の最初の試みは、次のようなメソッドを書くことでした

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

ただし、このメソッドをIDirect3DSurface9 *eg のようなものに適用すると、と互換性がないSafeRelease(&mySurface)というエラーが発生します。IDirect3DSurface9 **IUnknown **

  1. 私はここで何を間違っていますか?
  2. そのような関数を実装するためのより良いアプローチ (できればマクロを使用しない) はありますか?
4

3 に答える 3

1

これが私の方法です:

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

使用例:

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

必要inlineに応じて、この機能を使用できます。

于 2013-02-04T22:20:14.743 に答える
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 に設定して起動することに注意してください。これら 2 つのオブジェクトは、main() 内のオブジェクトではなく、クラスのメンバーである可能性があります。

于 2013-02-04T21:53:27.077 に答える
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**これが、 to以外の型のキャストがT**許可されていない理由です。つまり、 type の変数には( type の値)T**のみを割り当てることができ、 aではありません。ppTT**ppSomeSubytpeOfT

これを比較してください:基底クラスへのポインターへの参照を期待している関数に、派生クラスへのポインターを渡すことができないのはなぜですか? そして、これ: Casting double pointers of base classes .

COMSafeReleaseの場合、テンプレート (ここで提案されているように) またはマクロで十分です。

于 2014-05-02T15:17:42.120 に答える