Приведение интерфейсов DirectX к указателям IUnknown

Имея в своем коде немало интерфейсов, я хотел инкапсулировать повторяющиеся Release код в другом методе, а не в макросе, потому что это C ++, и я ненавижу использовать макросы. Моей первоначальной попыткой было написать такой метод, как

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

Однако применение этого метода к IDirect3DSurface9 * например лайк SafeRelease(&mySurface) выдает ошибку IDirect3DSurface9 ** несовместимо с IUnknown **,

  1. Что я здесь делаю не так?
  2. Есть ли лучший подход (надеюсь, не используя макросы) для реализации такой функции?

1

Решение

Вот мой метод:

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

Пример использования:

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

Ты можешь inline эта функция, если хотите.

1

Другие решения

Вы можете использовать шаблон:

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

Обратите внимание, что они используют один и тот же Releaser, и обратите внимание, что вызов функции surface.reset () также освободит интерфейс и установит указатель внутри unique_ptr на null для загрузки. Эти два объекта могут быть членами вашего класса, а не объектами в main ().

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 (значение типа T**) а не ppSomeSubytpeOfT,

Сравните это: Почему указатель на производный класс не может быть передан функции, ожидающей ссылку на указатель на базовый класс? И этот: Кастинг двойных указателей базовых классов.

Для COM SafeReleaseподойдет либо шаблон (как предложено здесь), либо макрос.

0
По вопросам рекламы [email protected]