向左右向右走 —— 小时了了的技术博客

关注C++开发技术、架构设计、软件项目管理、软件产品管理等

posts - 24,comments - 59,views - 36166

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

 

2016.03.12 补充:ComPtr 还有一个 ReleaseAndGetAddressOf 方法, out 语义的参数可以用这个方法取指针地址。而 ComPtr::operator& 方法返回的实际上是 ComPtr 对象指针的一个包装类,该包装类在转换为 void** 或者 T** 时实际上也是调用了 ComPtr::ReleaseAndGetAddressOf 方法。

 

posted on   小时了了  阅读(1877)  评论(1编辑  收藏  举报
编辑推荐:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· 【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

点击右上角即可分享
微信分享提示