DirectX11--ComPtr智能指针

综述

DirectX11 With Windows SDK完整目录html

欢迎加入QQ群: 727623616 能够一块儿探讨DX11,以及有什么问题也能够在这里汇报。框架

IUnknown接口类

DirectX11的API是由一系列的COM组件来管理的,这些前缀带I的接口类最终都继承自IUnknown接口类。IUnknown的三个方法以下:函数

方法 描述
IUnknown::AddRef 内部引用计数加1。在每次复制了一个这样的指针后,应当调用该方法以保证计数准确性
IUnknown::QueryInterface 查询该实例是否实现了另外一个接口,若是存在则返回该接口的指针,而且对该接口的引用计数加1
IUnknown::Release 内部引用数减1。只有当内部引用数到达0时才会真正释放

在实际的使用状况来看,一般咱们几乎不会使用第一个方法。而用的最多的就是第三个方法了,每次用完该实例后,咱们必需要使用相似下面的宏来释放:3d

#define ReleaseCOM(x) { if(x){ x->Release(); x = nullptr; } }

并且若是出现了忘记释放某个接口指针的状况话,内存泄漏的提醒就有可可以你去调试一成天了。指针

ComPtr智能指针

为了解决上述问题,从繁杂的人工释放中解脱,在本教程中大量使用了ComPtr智能指针。并且在龙书12的教程源码中也用到了该智能指针。该智能指针能够帮助咱们来管理这些COM组件实现的接口实例,而无需过多担忧内存的泄漏。该智能指针的大小和通常的指针大小是一致的,没有额外的内存空间占用。因此本教程能够不须要用到接口类ID3D11Debug来协助检查内存泄漏。调试

使用该智能指针须要包含头文件wrl/client.h,而且智能指针类模板ComPtr位于名称空间Microsoft::WRL内。code

首先有五个比较经常使用的方法须要了解一下:htm

方法 描述
ComPtr ::Get 该方法返回T*,而且不会触发引用计数加1,经常使用在COM组件接口的函数输入
ComPtr ::GetAddressOf 该方法返回T**,经常使用在COM组件接口的函数输出
ComPtr ::Reset 该方法对里面的实例调用Release方法,并将指针置为nullptr
ComPtr ::ReleaseAndGetAddressOf 该方法至关于先调用Reset方法,再调用GetAddressOf方法获取T**,经常使用在COM组件接口的函数输出,适用于实例可能会被反复构造的状况下
ComPtr ::As 一个模板函数,能够替代IUnknown::QueryInterface的调用,须要传递一个ComPtr实例的地址

而后是一些运算符重载的方法:blog

运算符 描述
& 至关于调用了ComPtr<T>::ReleaseAndGetAddressOf方法,不推荐使用
-> 和裸指针的行为一致
= 不要将裸指针指向的实例赋给它,若传递的是ComPtr 的不一样实例则发生交换
==和!= 能够和nullptr,或者另外一个ComPtr 实例进行比较

注意:大体在比10.0.16299.0更早的Windows SDK版本中,ComPtr使用了一个RemoveIUnknownBase类模板将IUnknown的三个接口都设为了private,以防止用户直接操做这些方法,这也就使得ComPtr没法直接使用COM组件的QueryInterface方法。所以,使用ComPtr<T>::As是一种合适的选择。继承

我的建议,在使用该智能指针后就应该要避免使用IUnknown提供的三个接口方法来进行操做。

虽然替换成ComPtr后代码量变长了,可是带来的收益确定比你本身花费大量时间在检查释放内存上强的多。

下面的D3DApp将全部COM组件指针都换成了ComPtr

class D3DApp
{
public:
    D3DApp(HINSTANCE hInstance);              // 在构造函数的初始化列表应当设置好初始参数
    virtual ~D3DApp();

    HINSTANCE AppInst()const;                 // 获取应用实例的句柄
    HWND      MainWnd()const;                 // 获取主窗口句柄
    float     AspectRatio()const;             // 获取屏幕宽高比

    int Run();                                // 运行程序,进行游戏主循环

                                              // 框架方法。客户派生类须要重载这些方法以实现特定的应用需求
    virtual bool Init();                      // 该父类方法须要初始化窗口和Direct3D部分
    virtual void OnResize();                  // 该父类方法须要在窗口大小变更的时候调用
    virtual void UpdateScene(float dt) = 0;   // 子类须要实现该方法,完成每一帧的更新
    virtual void DrawScene() = 0;             // 子类须要实现该方法,完成每一帧的绘制
    virtual LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    // 窗口的消息回调函数
protected:
    bool InitMainWindow();      // 窗口初始化
    bool InitDirect3D();        // Direct3D初始化

    void CalculateFrameStats(); // 计算每秒帧数并在窗口显示

protected:

    HINSTANCE m_hAppInst;        // 应用实例句柄
    HWND      m_hMainWnd;        // 主窗口句柄
    bool      m_AppPaused;       // 应用是否暂停
    bool      m_Minimized;       // 应用是否最小化
    bool      m_Maximized;       // 应用是否最大化
    bool      m_Resizing;        // 窗口大小是否变化
    bool      m_Enable4xMsaa;    // 是否开启4倍多重采样
    UINT      m_4xMsaaQuality;   // MSAA支持的质量等级


    GameTimer m_Timer;           // 计时器

    // 使用模板别名(C++11)简化类型名
    template <class T>
    using ComPtr = Microsoft::WRL::ComPtr<T>;
    // Direct3D 11
    ComPtr<ID3D11Device> m_pd3dDevice;                    // D3D11设备
    ComPtr<ID3D11DeviceContext> m_pd3dImmediateContext;   // D3D11设备上下文
    ComPtr<IDXGISwapChain> m_pSwapChain;                  // D3D11交换链
    // Direct3D 11.1
    ComPtr<ID3D11Device1> m_pd3dDevice1;                  // D3D11.1设备
    ComPtr<ID3D11DeviceContext1> m_pd3dImmediateContext1; // D3D11.1设备上下文
    ComPtr<IDXGISwapChain1> m_pSwapChain1;                // D3D11.1交换链
    // 经常使用资源
    ComPtr<ID3D11Texture2D> m_pDepthStencilBuffer;        // 深度模板缓冲区
    ComPtr<ID3D11RenderTargetView> m_pRenderTargetView;   // 渲染目标视图
    ComPtr<ID3D11DepthStencilView> m_pDepthStencilView;   // 深度模板视图
    D3D11_VIEWPORT m_ScreenViewport;                      // 视口

    // 派生类应该在构造函数设置好这些自定义的初始参数
    std::wstring m_MainWndCaption;                       // 主窗口标题
    int m_ClientWidth;                                   // 视口宽度
    int m_ClientHeight;                                  // 视口高度
};

DirectX11 With Windows SDK完整目录

欢迎加入QQ群: 727623616 能够一块儿探讨DX11,以及有什么问题也能够在这里汇报。

相关文章
相关标签/搜索