C++ DirectX不带->;释放()

C++ DirectX不带->;释放(),c++,memory-management,com,directx,C++,Memory Management,Com,Directx,编写DIY内存管理器最令人满意的部分是对其进行结构化,以便您可以忘记[delete](例如,通过将所有内容捆绑到单独分配/解除分配的缓冲区中) DirectX处理对象创建的方式意味着您不能简单地将无效内存强制转换为要生成的类型(可以吗?),而必须依赖COM(+记住在每个析构函数中[释放]本地内存)。有没有办法颠覆这一点,说服DirectX使用我的指针 而不是: ID3D12Thing* thng = DirectX::CreateThing(); ... thng->Release();

编写DIY内存管理器最令人满意的部分是对其进行结构化,以便您可以忘记[delete](例如,通过将所有内容捆绑到单独分配/解除分配的缓冲区中)

DirectX处理对象创建的方式意味着您不能简单地将无效内存强制转换为要生成的类型(可以吗?),而必须依赖COM(+记住在每个析构函数中[释放]本地内存)。有没有办法颠覆这一点,说服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.答案下的评论部分)/Edit

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

然而,如果主要目标是维护和安全,则可以使用自定义删除程序定义
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; 
...

在这种情况下,您必须始终确保使用
dx\u device\u shared myDevice=assignDevice(myRawDevicePtr)
分配创建的设备,但决不能使用
dx\u device\u shared myDevice=myRawDevicePtr
TL;DR:使用智能指针,如。


我非常喜欢
std::unique_ptr
std::shared_ptr
,但它们都没有真正正确地处理COM对象,例如具有自己内置引用计数的Direct3D接口。更好的选择是使用WRL类
Microsoft::WRL::ComPtr
或C++/WinRT类
WinRT::com_ptr

一些老程序员可能会建议使用旧的ATL
CComPtr
,但更现代的
Microsoft::WRL::ComPtr
是更好的选择


微软最近发布了一个新的C++库。它包括:

wil::com_ptr thng{DirectX::CreateThing())};

DirectX(包括Direct3D和相关API)有自己的内存管理器,用于创建自己的对象。包括未向您公开的内部对象。所以不,你不太可能做到。我怀疑这是可能的。但是,如果您的主要目标是减少维护,那么显而易见的解决方案是将
std::unique_ptr
与执行
release()
的自定义删除程序一起使用。如果你是这个意思,我可以发布一个答案。@user2328447是的,这可能很有趣-任何让我集中处理交易的东西都是好的:)那么你实际上不喜欢智能指针和RAII。在C++领域,人们会因为这样的事情而被钉死在十字架上。谢谢,这(几乎)正是我想要的:)我可以写一些东西来跟踪每次分配的情况并记录分配的金额吗?在某个地方设置内存使用阈值并准确知道我在每个调试会话中将要使用多少内存是很好的。抱歉,我不知道如何询问DirectX项目的实际大小-但是如果您找到一种方法,您当然可以跟踪内存。啊啊啊……好的。是时候问另一个问题了:)。(我想我误读了你的评论,顺便说一句-我以为你控制了分配而不是删除)。对不起,我不知道:(WinRT/WRL类型等效吗?我的引擎中没有使用WinRT,但我可能会将一些代码用于学校事务,如果它们可以互换就好了:)WRL是一个C++模板库, COMPTR 类完全是C++,它与普通的旧COM一起工作。您可以在Windows 7、UWP或Xbox One上的Win32桌面应用程序中使用它。C++/WinRT类基本上是与
ComPtr
相同的助手,如果您愿意,可以在C++/WinRT项目中使用
ComPtr
。我感兴趣的是
std::unique_ptr
std::shared_ptr
的问题是什么。据我所知,他们分配和发布项目的方式与手动分配和发布项目的方式完全相同(这显然是可以的),但没有麻烦。所以我不得不承认我不理解这个问题。我已经搜索过了,但结果却很矛盾。您能否进一步解释一下(也许可以扩展您的答案)?
std::unique\u ptr
假设为单一所有者模型。使用COM对象,您可以拥有多个共享所有者
std::shared_ptr
使用它自己的引用计数(外部分配),而不是已经是COM
IUnknown
的一部分的引用计数,因此它可能与“真实”计数不同步
ComPtr
AddRef
Release
方面做了正确的事情,并且理解了
QueryInterface
接口多态性的工作原理。@ChuckWalbourn很棒,这让事情变得更简单了^_^
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 ) );
}