DirectX11--ComPtr智能指针
综述
DirectX11 With Windows SDK完整目录
欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。
IUnknown接口类
DirectX11的API是由一系列的COM组件来管理的,这些前缀带I的接口类最终都继承自IUnknown接口类。IUnknown的三个方法如下:
| 方法 | 描述 |
|---|---|
| IUnknown::AddRef | 内部引用计数加1。在每次复制了一个这样的指针后,应当调用该方法以保证计数准确性 |
| IUnknown::QueryInterface | 查询该实例是否实现了另一个接口,如果存在则返回该接口的指针,并且对该接口的引用计数加1 |
| IUnknown::Release | 内部引用数减1。只有当内部引用数到达0时才会真正释放 |
在实际的使用情况来看,通常我们几乎不会使用第一个方法。而用的最多的就是第三个方法了,每次用完该实例后,我们必须要使用类似下面的宏来释放:
#define ReleaseCOM(x) { if(x){ x->Release(); x = nullptr; } }
而且如果出现了忘记释放某个接口指针的情况话,内存泄漏的提醒就有可能够你去调试一整天了。
ComPtr智能指针
为了解决上述问题,从繁杂的人工释放中解脱,在本教程中大量使用了ComPtr智能指针。而且在龙书12的教程源码中也用到了该智能指针。该智能指针可以帮助我们来管理这些COM组件实现的接口实例,而无需过多担心内存的泄漏。该智能指针的大小和一般的指针大小是一致的,没有额外的内存空间占用。所以本教程可以不需要用到接口类ID3D11Debug来协助检查内存泄漏。
使用该智能指针需要包含头文件wrl/client.h,并且智能指针类模板ComPtr位于名称空间Microsoft::WRL内。
首先有五个比较常用的方法需要了解一下:
| 方法 | 描述 |
|---|---|
| ComPtr::Get | 该方法返回T*,并且不会触发引用计数加1,常用在COM组件接口的函数输入 |
| ComPtr::GetAddressOf | 该方法返回T**,常用在COM组件接口的函数输出 |
| ComPtr::Reset | 该方法对里面的实例调用Release方法,并将指针置为nullptr |
| ComPtr::ReleaseAndGetAddressOf | 该方法相当于先调用Reset方法,再调用GetAddressOf方法获取T**,常用在COM组件接口的函数输出,适用于实例可能会被反复构造的情况下 |
| ComPtr::As | 一个模板函数,可以替代IUnknown::QueryInterface的调用,需要传递一个ComPtr实例的地址 |
然后是一些运算符重载的方法:
| 运算符 | 描述 |
|---|---|
| & | 相当于调用了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,以及有什么问题也可以在这里汇报。
DirectX11--ComPtr智能指针的更多相关文章
- enote笔记法使用范例(2)——指针(1)智能指针
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- C++智能指针
引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...
- EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针
一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...
- 智能指针shared_ptr的用法
为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...
- 智能指针unique_ptr的用法
unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...
- 基于C/S架构的3D对战网络游戏C++框架_05搭建系统开发环境与Boost智能指针、内存池初步了解
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- C++ 引用计数技术及智能指针的简单实现
一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...
- C++11智能指针读书笔记;
智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...
随机推荐
- 好代码是管出来的——.Net Core中的单元测试与代码覆盖率
测试对于软件来说,是保证其质量的一个重要过程,而测试又分为很多种,单元测试.集成测试.系统测试.压力测试等等,不同的测试的测试粒度和测试目标也不同,如单元测试关注每一行代码,集成测试关注的是多个模块是 ...
- 网页验证码出不来,读取验证码时出错:javax.imageio.IIOException: Can't create cache file!
版权声明:本文为博主原创文章,仅作为学习交流使用 转载请注明出处 https://www.cnblogs.com/linck/p/10593053.html 今天打开项目时,发现登陆界面的验证码出不来 ...
- vue笔记未整理
全局组件 局部组件 子组件传值到父组件 父子组件传值 watch跟计算属性差不多,都会有缓存,计算属性优先 计算属性get set 对象 数组 对象 数组 不复用 改变数组 直接修改数组,页面没变化 ...
- Ubuntu server 16.04的安装 以及配置(服务器版)
1.在电脑上下载最新版本的Ubuntu服务器ISO映像,刻录到CD或创建一个可启动的USB盘. 2.视情况而定,进入到服务器的boot界面,把cd或者usb设置为启动第一项 3.开始安装 1)Ub ...
- Visual Studio 2019 正式版 更新内容
大早上更新了Visual Studio 2019, 试用一下 一.界面改变 1.项目创建界面 首先启动界面改变就不说了,创建项目的界面做了较大改变,感觉在向vs for mac 靠拢 ,而后者感觉像x ...
- 随心测试_数据库_002 <数据库系统组成>
软测工程师:作为综合运用多学科知识,保障软件质量的重要岗位.需要我们学以致用,在工作中不断学习提升.以下:软测人员必备_数据库核心技能学习点,供大家学习参考. 数据库系统组成_必备 1. 简介:数据库 ...
- ABP之什么是ABP(ASP.NET Boilerplate)
1.介绍 ABP是开源的且文档比较齐全的应用程序框架.其实它不仅仅是个框架,考虑其最佳实践,ABP更提供了基于领域驱动设计(DDD)的强大价格模型. ABP支持最新的ASP.NET Core和EF C ...
- python中使用redis发布订阅者模型
redis发布订阅者模型: Redis提供了发布订阅功能,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel.发布者和订阅者都是Redis客户端,Channel则 ...
- VS2019 实用设置
本文记录了 VS2019 预览版使用过程中的一些设置,这些设置也同样适用于 VS2017,我们可以根据个人的实际情况进行修改. 滚动条(Scroll Bar) 将滚动条设置为 map mode 后,则 ...
- 启用k8s metrics server监控
1.创建aggregator证书 方法一:直接使用二进制源码包安装 $ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 $ chmod +x cfs ...