【问题标题】:DirectX, reference counts, and smart pointersDirectX、引用计数和智能指针
【发布时间】:2015-01-27 01:01:45
【问题描述】:

我正在使用 C++ 构建游戏,为了防止内存泄漏,我想确保从一开始就正确地完成所有操作。

目前,我有一个 D3D 类,其中包含我所有的 direct3D 内容。

但是,我的 Render() 方法在某些时候需要访问 DeviceContext。为此,我的 D3D 类必须从自身内部返回 ID3D11DeviceContext 指针。这意味着我有另一个对该 COM 对象的引用,而没有增加它的引用计数。

例如:

Render()
{
    m_d3d.GetDevCon()->DoWhatever();
}

我可以这样使用它,这意味着我永远不必制作指针的外部副本吗?这会安全吗?我可以做些什么来保护我的程序免受坏事的影响,例如:

Render()
{
    ID3D11DeviceContext* devCon = m_d3d.GetDevCon();
    devCon->DoWhatever();
}

我可以看到这意味着引用计数与实际引用数不匹配。

基本上我想尽量避免使用原始指针。我想掌握的不仅仅是使用智能指针,而是知道何时使用它们。

【问题讨论】:

  • 为什么渲染类中的 std::unique_ptr 不能解决您需要的问题?
  • 它可能会,但是我对智能指针的了解很模糊,以至于我对如何使用它们一无所知。
  • 听起来你试图阻止指针就位;考虑让 GetDevCon 返回对 DeviceContext 的引用而不是指针。
  • 所以 ID3D11DeviceContext& cD3D::GetDevCon() { return *m_devCon; } ?你也能为我定义“坐着”吗?术语从来都不是我的强项

标签: c++ windows-7-x64 smart-pointers directx-11


【解决方案1】:

对于像 Direct3D 对象这样的 COM 对象,您应该使用智能指针 Microsoft::WRL::ComPtr(可与 Windows 8.x SDK 在所有 C++ 应用程序中使用,包括 Win32 桌面应用程序)。

std::unique_ptr 非常适合多种用途,std::shared_ptr 也是如此,但它们不适用于 COM 对象。

下面的代码是“安全的”,可以在不增加引用计数的情况下使用原始指针,只要您没有另一个线程可能释放ID3D11DeviceContext 足以被释放。这将是一个奇怪的程序,它会从您正在运行渲染的线程之外的线程中执行此操作。

Render()
{
    ID3D11DeviceContext* devCon = m_d3d.GetDevCon();
    devCon->DoWhatever();
}

换句话说,在更新/渲染/呈现的标准游戏循环中,您不需要创建“强引用”(即增加引用计数)只是为了使用它进行渲染,您可以安全地使用“弱引用”引用'(即不增加引用计数的指针),只要您有一个明确的初始化过程,设备/上下文只能在该游戏循环中的特定点被销毁和/或重新创建(即不在更新中间或渲染,但可能是对失败的 Present 的响应)。

请参阅Smart Pointers (Modern C++)Direct3D Win32 Game Visual Studio template 了解更多信息。

您可能会在 this 文章中找到有用的智能指针的各种“异常安全”用法示例。

【讨论】:

  • 我正在尝试使其内存安全,而不会对性能造成太大影响。它在我使用时非常安全,因为我是一个相当明智的程序员,但我最终打算将它开放给其他人的贡献,并且我想设置它以使其不易出错。跨度>
  • 与将 ID3D11DeviceContext* 包装在 cD3D 中并从方法中返回(取消引用)相比,直接在 cMain 中使用 ID3D11DeviceContext* 有多快?
  • 在除了最琐碎的绘图案例之外的所有情况下,像这样的事情将与游戏中的绘图时间和其他计算相形见绌。也就是说,您不希望增加引用计数,然后不必要地减少同一帧中的这些计数。使用Microsoft::WRL::ComPtr 而不是一些家庭制造的愚蠢的 COM 智能指针。
  • ComPtr 对我不可用,我使用的是 vs 2012 附带的 Windows SDK。我阅读的每个指南似乎也表明 ComPtr 只能用于 WinRT 应用程序,当我为 Windows 7 编写
  • Microsoft::WRL::ComPtr 与 VS 2012/VS2013 附带的 Windows 8.x SDK 一起完美适用于 Windows Vista 或 Windows 7 或更高版本上的 Win32 桌面应用程序。它没有二进制依赖并且是完全内联的——与 ATL CComPtr 不同。就用它吧。
猜你喜欢
  • 2016-09-14
  • 1970-01-01
  • 2012-12-10
  • 2015-10-30
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-18
相关资源
最近更新 更多