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 的坑的更多相关文章

  1. UWP开发细节记录:DirectX::XMMATRIX 的坑

    这两天写的代码概率性的崩溃在 XMMatrixMultiply() 函数,XMMatrixMultiply() 本身是 inline 函数可以看到崩溃处的代码: vX = _mm_mul_ps(vX, ...

  2. UWP开发细节记录:加载图像文件到D2D位图和D3D纹理

    在UWP中加载文件一般先创建 StorageFile 对象,然后调用StorageFile.OpenReadAsync 方法得到一个IRandomAccessStream 接口用来读取数据: Stor ...

  3. UWP开发细节记录:IStream 和 IRandomAccessStream^ 以及 IMFByteStream 互转

    IStream 和 IRandomAccessStream^ 互转 IRandomAccessStream^ --> IStream:  CreateStreamOverRandomAccess ...

  4. UWP开发细节记录:判断文件类型

    StorageFile.ContentType 属性,是 string 类型,用来表示文件内容的 MIME 类型.例如,音乐文件可能有 "audio/mpeg" MIME 类型.( ...

  5. 记UWP开发——多线程操作/并发操作中的坑

    一切都要从新版风车动漫UWP的图片缓存功能说起. 起因便是风车动漫官网的番剧更新都很慢,所以图片更新也非常慢.在开发新版的过程中,我很简单就想到了图片多次重复下载导致的资源浪费问题. 所以我给app加 ...

  6. PC客户端开发细节记录:保存GUID到VARIANT

    有两个 API 可以实现保存 GUID 到 VARIANT InitVariantFromGUIDAsBuffer 以字节数组形式保存,保存类型为 VT_ARRAY | VT_UI1,相当于字节拷贝, ...

  7. java后台开发细节记录

    1.  ResultMap是程序员控制SQL查询结果和实体类的映射关系,而不是sql语句中字段的重命名,所以在sql语句中还是要按照原来字段的格式进行书写.

  8. 讲讲我在Windows10(uwp)开发中遇到的一些坑.

    7月29日发布的Windows10正式版,当天安装好以后,在网络不太好的情况下,经过多次尝试终于装上了Visual Studio 2015和Windows 10 10240的SDK.这两周一直在开发U ...

  9. 领域驱动和MVVM应用于UWP开发的一些思考

    领域驱动和MVVM应用于UWP开发的一些思考 0x00 起因 有段时间没写博客了,其实最近本来是根据梳理的MSDN上的资料(UWP开发目录整理)有条不紊的进行UWP学习的.学习中有了心得体会或遇到了问 ...

随机推荐

  1. logstash笔记(一)——redis&es

    下载地址: https://www.elastic.co/downloads 版本:logstash-2.2.2 两台linux虚拟机,一台windows宿主机 shipper: 192.168.22 ...

  2. Apache Oltu 实现 OAuth2.0 服务端【授权码模式(Authorization Code)】

    要实现OAuth服务端,就得先理解客户端的调用流程,服务提供商实现可能也有些区别,实现OAuth服务端的方式很多,具体可能看 http://oauth.net/code/ 各语言的实现有(我使用了Ap ...

  3. todolist增加markdown模块

    markdown编辑器 利用`markdown_js`开源库实现todolist小项目的markdown日记本功能 todolist小项目地址 之前的介绍随笔todoList markdown-js仓 ...

  4. 【转】多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)

    本篇从Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler的类关系图开始,希望通过 本篇的介绍能对常见的线程同步方法有一个整体的认识,而对 ...

  5. Tensorflow应用之LSTM

    学习RNN时原理理解起来不难,但是用TensorFlow去实现时被它各种数据的shape弄得晕头转向.现在就结合一个情感分析的案例来了解一下LSTM的操作流程. 一.深度学习在自然语言处理中的应用 自 ...

  6. java命令行指定log4j2

    java -Dlog4j.configurationFile=directory/file.xml

  7. JDBC中链接数据库前为什么要用Class.forName(驱动类)加载驱动类?

    使用JDBC链接数据库时,为什么要先使用Class.forName(String name)来加载类? 答: 实际上就是为了加载类时,调用静态初始化块中的注册函数. 可以看一下MySql的Driber ...

  8. A Personal Understanding to Matrix Transformation in Graphics

    A Personal Understanding to Matrix Transformation in Graphics--------------------------------------- ...

  9. DOS在这里

    转自: http://blog.csdn.net/rheostat/article/details/8043835 在右键菜单中添加Dos快捷通道-dos在这里 在右键菜单中添加 Dos 窗体 不用每 ...

  10. tomcat之日志切割

    日志分割 场景:日志量比较大,且研发程序没有设置分卷 1.配置样例: 文件路径:/etc/logrotate.d/tomcat /data/logs/catalina.out { daily comp ...