UWP开发细节记录:WRL::ComPtr 的坑
WRL::ComPtr 取原始指针的地址有两种方式:
- operator&() 先释放原指针再取地址
- GetAddressOf() 直接得到原始指针的地址
显然,operator& 是为COM风格的API设计的,比如下面这种:
HRESULT CreateObject(/* [out] */IUnknown** ppObj);
在这一点上和 ATL::CComPtr 一致,实现上则有不同。上面这种 API 最容易出现的错误是传了一个非空指针的地址给 ppObj ,然后指针被覆盖导致原来指向的对象无法释放。ATL::CComPtr 的解决办法是在 operator& 的实现中加了一个断言,如果指针非空就弹出警告;WRL::ComPtr 的解决办法如上所述,先释放再取地址。
从使用的角度 WRL::ComPtr 更方便,但从设计角度看实际上违背了运算符重载的基本原则。在不看文档的情况下没人能预期到 operator& 会修改原指针的值,这就是坑。
如下面这样一个 API:
HRESUTL SetObjects(/* [in] */IUnknown** ppObjs, /* [in] */int count);
双重指针参数实际代表的是一个指针数组,而非类似 CreateObject 中的指针地址。在数组长度为 1 时,习惯上直接取指针地址设为 ppObjs 参数,然后将 count 设为1 ,如下:
IUnknown* ptr = NULL; // 正确
// ATL::CComPtr<IUnknown> ptr; // 警告
// WRL::ComPtr<IUnknown> ptr; // 悲剧 CreateObject(&ptr);
SetOjbects(&ptr, ); // 注意这里
注意第六行的代码,无论 ptr 是裸指针还是ATL::CComPtr 包装的智能指针都正确的,不过 CComPtr 会引发断言失败使得我们不得不修改成其他实现方式;WRL::ComPtr 智能指针则编译运行一切正常结果却是悲剧。
以后使用 WRL::ComPtr 只能小心些了,只在 out 语义的参数中使用 operator& 其他一律用 GetAddressOf ,或者全部用 GetAddressOf 然后在用作 out 语义的参数前写断言。
设计上的小聪明还是要不得,哪怕是微软。
MSDN 中关于 ComPtr::operator& 运算符的备注说明 :
This method differs from ComPtr::GetAddressOf in that this method releases a reference to the interface pointer.Use ComPtr::GetAddressOf when you require the address of the interface pointer but do not want to release that interface.
https://msdn.microsoft.com/zh-cn/library/vs/alm/br230430.aspx
2016.03.12 补充:ComPtr 还有一个 ReleaseAndGetAddressOf 方法, out 语义的参数可以用这个方法取指针地址。而 ComPtr::operator& 方法返回的实际上是 ComPtr 对象指针的一个包装类,该包装类在转换为 void** 或者 T** 时实际上也是调用了 ComPtr::ReleaseAndGetAddressOf 方法。
UWP开发细节记录:WRL::ComPtr 的坑的更多相关文章
- UWP开发细节记录:DirectX::XMMATRIX 的坑
这两天写的代码概率性的崩溃在 XMMatrixMultiply() 函数,XMMatrixMultiply() 本身是 inline 函数可以看到崩溃处的代码: vX = _mm_mul_ps(vX, ...
- UWP开发细节记录:加载图像文件到D2D位图和D3D纹理
在UWP中加载文件一般先创建 StorageFile 对象,然后调用StorageFile.OpenReadAsync 方法得到一个IRandomAccessStream 接口用来读取数据: Stor ...
- UWP开发细节记录:IStream 和 IRandomAccessStream^ 以及 IMFByteStream 互转
IStream 和 IRandomAccessStream^ 互转 IRandomAccessStream^ --> IStream: CreateStreamOverRandomAccess ...
- UWP开发细节记录:判断文件类型
StorageFile.ContentType 属性,是 string 类型,用来表示文件内容的 MIME 类型.例如,音乐文件可能有 "audio/mpeg" MIME 类型.( ...
- 记UWP开发——多线程操作/并发操作中的坑
一切都要从新版风车动漫UWP的图片缓存功能说起. 起因便是风车动漫官网的番剧更新都很慢,所以图片更新也非常慢.在开发新版的过程中,我很简单就想到了图片多次重复下载导致的资源浪费问题. 所以我给app加 ...
- PC客户端开发细节记录:保存GUID到VARIANT
有两个 API 可以实现保存 GUID 到 VARIANT InitVariantFromGUIDAsBuffer 以字节数组形式保存,保存类型为 VT_ARRAY | VT_UI1,相当于字节拷贝, ...
- java后台开发细节记录
1. ResultMap是程序员控制SQL查询结果和实体类的映射关系,而不是sql语句中字段的重命名,所以在sql语句中还是要按照原来字段的格式进行书写.
- 讲讲我在Windows10(uwp)开发中遇到的一些坑.
7月29日发布的Windows10正式版,当天安装好以后,在网络不太好的情况下,经过多次尝试终于装上了Visual Studio 2015和Windows 10 10240的SDK.这两周一直在开发U ...
- 领域驱动和MVVM应用于UWP开发的一些思考
领域驱动和MVVM应用于UWP开发的一些思考 0x00 起因 有段时间没写博客了,其实最近本来是根据梳理的MSDN上的资料(UWP开发目录整理)有条不紊的进行UWP学习的.学习中有了心得体会或遇到了问 ...
随机推荐
- Hibernate的集合一对多与多对一
需求: 部门与员工 一个部门有多个员工; [一对多] 多个员工,属于一个部门 [多对一] 1.javaBean ——Dept.java package com.gqx.oneto ...
- spring boot 与 自定义interceptor
前面学习过过滤器, 但是过滤器是针对servlet的, 用在springmvc和spring boot里面, 功能上, 感觉并不是很好用. 那这里来学习一下拦截器. 一. 拦截器的执行顺序 1. 目录 ...
- ASP.NET MVC View中的标签(tag)
在编辑View的时候会用到各种HTML标签,如<a>,<input>,<p>等待,这些标签在ASP.NET MVC中都有对应的编程语法,它叫Razor,它是帮助我们 ...
- NHibernate with ASP.NET MVC 入门示例
目的:初步了解NHibernate的用法,包括数据库的CRUD, 基于ASP.NET MVC 项目模板 步骤: 创建ASP.NET MVC 新项目 使用NuGet引入FluentNHibernate ...
- 第一次项目上Linux服务器(五:CentOS7下Mysql数据库的安装与配置(转))
好像在CentOS 7系统中,默认安装的mysql是它的分支mariadb.所以不能像CentOS-6.3那样安装,如下: [root@izwz ~]# yum -y install mysql my ...
- linux系统被ddos攻击识别
通过查看dmesg日志信息,当存在大量如下 的信息,服务器开始响应缓慢并丢失正常的计数数据.这是典型的SYN Flood攻击(或开放半连接攻击). [ [ [ [ [ [ [ TCP洪水攻击(SYN ...
- How to describe the wind sprial in computer system?
How to describe the wind sprial in computer system? 2017-02-21 刘崇军 风螺旋线 If we want get the approval ...
- CodeForces -977F(突破定式思维+map应用)
题目链接: https://cn.vjudge.net/problem/CodeForces-977F /* 问题 输入n和n个数的数列 计算并输出最长增量为1的上升子序列 解题思路 用n2的最长上升 ...
- laravel 文件上传
laravel 文件上传 先开扩展 表单中能够选择图片 数据处理C层, 接图片并保存 保存图片: 设置目录 store()的第一个参数说明: 存放图片的子目录. 如何获取文件的类型 大小: $uplo ...
- Html.DropDownListFor练习(2)
下午有做了练习<Html.DropDownListFor练习>http://www.cnblogs.com/insus/p/3382575.html 在实现过程中,需要创建一个List&l ...