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)建立的指针 它的一种通用实现 ...
随机推荐
- curl 命令-接口测试
在linux/Unix 为代表的os上, 对后端进行测试, 模拟连接请求都会书写脚本 场景: 在Linux 上接口测试工具有ab, restClient, postman等, 最常用的方法是curl进 ...
- BASE64编码的图片在网页中的显示问题的解决
BASE64位转码有两种: 一种是图片转为Base64编码,这种编码是直接可以在页面通过<img src='base64编码'/>的方式显示 Base64 在CSS中的使用 .demoIm ...
- mssql sqlserver 将字段null(空值)值替换为指定值的三种方法分享
摘要: 下文将分享两种将字段中null值替换为指定值的方法分享,如下所示: 实验环境:sqlserver 2008 R2 例: )) go insert into test(info)values(' ...
- FPGA设计千兆以太网MAC(2)——以太网协议及设计规划
上篇该系列博文中通过MDIO接口实现了PHY芯片的状态检测,验证其已处于1000M 全双工工作模式.在设计MAC逻辑之前,要先清楚MAC与PHY之间的接口以及以太网协议细节,这样才能保证网络的兼容性. ...
- python学习——读取染色体长度(四:获取最长染色体的编号)
# 读取fasta # 解析每条序列的长度 chr_len = {'chr1':10,'chr2':20,'chr3':30,'chr4':40,'chr5':15} # 求和 total_len = ...
- 1 Openwrt无线中继设置并访问外网
https://www.cnblogs.com/wsine/p/5238465.html 配置目标 主路由器使用AP模式发射Wifi 从路由器使用Client模式接受Wifi 从路由器使用Master ...
- [BJOI2019]光线[递推]
题意 题目链接 分析 令 \(f_i\) 表示光线第一次从第一块玻璃射出第 \(i\) 块玻璃的比率. 令 \(g_i\) 表示光线射回第 \(i\) 块玻璃,再射出第 \(i\) 块玻璃的比率. 容 ...
- Spring boot的第一个demo
由于SpringBoot的问世使开发的门槛有降低了不少,就其这一点,早已使其名声大振,如雷贯耳.我之前是使用spring开发的,刚才使用了spring boot试验了一下,果然名不虚传,开发速度贼快. ...
- Node.js Error: Cannot find module express的解决办法
1.全局安装express框架,cmd打开命令行,输入如下命令: npm install -g express express 4.x版本中将命令工具分出来,安装一个命令工具,执行命令: npm in ...
- c提高第五次作业
重写结构体嵌套一级指针老师和二级指针学生的代码 //结构体类型,每个导师有三个学生 typedef struct Teacher { char *tName; //导师 char **stu; //三 ...