没有 ->Release() 的 DirectX

DirectX without ->Release()

编写 DIY 内存管理器最令人满意的部分是构建它,这样您就可以忘记 [删除](例如,将所有内容捆绑到一个单独的 allocated/deallocated 缓冲区中)。

DirectX 处理对象创建的方式意味着您不能简单地将无效内存转换为您想要创建的类型(可以吗?)并且您必须依赖 COM(+ 记住 [Release] 本地内存每个析构函数)代替。有什么办法可以颠覆这一点并说服 DirectX 使用我的指针吗?

而不是:

ID3D12Thing* thng = DirectX::CreateThing();
...
thng->Release();
thng = nullptr;

我要:

ID3D12Thing* thng = DirectX::CreateThingAt(Allocator->AlignedAlloc(sizeof(ID3D12Thing));
...
[memory emptied during shutdown]

编辑:此答案已被 Chuck Walbourn 的平行答案取代。 虽然我的回答并非完全错误,但经过一些调查后,我很确定 Chuck Walbourn 使用 Microsoft::WRL::ComPtr 的建议是更好的选择(另请参阅 C.B 下的评论部分。原因的答案)。 /编辑

据我所知,不可能在 Direct X 结构上植入外部存储器,因为它们都是由 Direct X 本身创建的。

然而,如果主要目标是维护和安全,则可以定义一个 std::unique_ptr 带有自定义删除器来完成释放工作。

struct DxDeleter {
    void operator() (IUnknown* _moribund) { if(_moribund) _moribund->Release(); }
};
typedef std::unique_ptr<ID3D11Buffer,DxDeleter>                 dx_buffer_ptr; 
typedef std::unique_ptr<ID3D11ShaderResourceView,DxDeleter>     dx_resource_ptr; 
typedef std::unique_ptr<ID3D11UnorderedAccessView,DxDeleter>    dx_access_ptr; 
...

然后指针被简单地分配为例如。 myUniqueDxBufferPtr.reset( myRawBufferPtr ) 或类似的。

这有很大的好处,不需要跟踪版本。这不仅适用于 Direct X,而且适用于各种需要分配和释放的外部库(例如,我对 Freeimage 和 ffmpeg 也使用相同的技术)。

也可以为多个项目共享的资源定义 std::shared_ptrs(例如,只要存在任何缓冲区,您就可以让您的设备保持活动状态)。但这是 小心处理 - 与 std::unique_ptr 相反,std::shared_ptrs 没有 deleter 作为模板参数,而是作为 ctor 参数 -这使得错误地分配缺少删除器(泄漏)的东西变得非常容易。

void g_dxDelete( IUnknown* _moribund ) {
    if( _moribund )
        _moribund->Release();
}

typedef std::shared_ptr<ID3D11Device> dx_device_shared;
inline dx_device_shared assignDevice( ID3D11Device* _device ) {
    return std::move( dx_device_shared( _device, g_dxDelete ) );
}

在那种情况下,您必须始终确保将创建的设备分配给 dx_device_shared myDevice = assignDevice(myRawDevicePtr),但绝不能分配给 dx_device_shared myDevice = myRawDevicePtr

TL;DR: 使用像 ComPtr.

这样的智能指针

我是 std::unique_ptrstd::shared_ptr 的忠实粉丝,但它们都不能真正正确地处理 COM 对象,例如具有自己内置引用计数的 Direct3D 接口。更好的选择是使用 WRL class Microsoft::WRL::ComPtr 或 C++/WinRT class winrt::com_ptr.

Some older coders might suggest the old ATL CComPtr, but the more modern Microsoft::WRL::ComPtr is a better choice.

Microsoft 最近发布了一个新库 (WIL) for modern C++. It includes a new com pointer type:

wil::com_ptr<ID3D12Thing> thng{DirectX::CreateThing())};