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

    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 方法。

    作者:小时了了
    原创文章,欢迎转载,但请以链接形式注明本文地址.
  • 相关阅读:
    CC初试啼声-----演讲与我
    static关键字修饰类
    maven可选依赖(Optional Dependencies)和依赖排除(Dependency Exclusions)
    Installation Directory must be on a local hard drive解决办法
    回顾JDBC
    java中的定时器
    怎么删除windows中无用的服务
    java实现简单的素数判断
    SQL注入
    @Override must override a superclass method 问题解决
  • 原文地址:https://www.cnblogs.com/xrunning/p/5246263.html
Copyright © 2020-2023  润新知