首页 > 其他 > 详细

UWP开发细节记录:WRL::ComPtr 的坑

时间:2016-03-06 00:56:19      阅读:200      评论:0      收藏:0      [点我收藏+]

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 ,如下:

1 IUnknown* ptr = NULL;           // 正确
2 // ATL::CComPtr<IUnknown> ptr;  // 警告
3 // WRL::ComPtr<IUnknown> ptr;   // 悲剧
4 
5 CreateObject(&ptr);
6 SetOjbects(&ptr, 1);        // 注意这里

注意第六行的代码,无论 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

 

UWP开发细节记录:WRL::ComPtr 的坑

原文:http://www.cnblogs.com/xrunning/p/5246263.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!