`wil::com_ptr` 是否会重载运算符 &,又名 "address of"?

Does `wil::com_ptr` overload operator &, aka "address of"?

我找到了这段代码 here

wil::com_ptr<IStream> stream;
CHECK_FAILURE(SHCreateStreamOnFileEx(
    L"assets/EdgeWebView2-80.jpg", STGM_READ, FILE_ATTRIBUTE_NORMAL,
    FALSE, nullptr, &stream));

根据 SHCreateStreamOnFileExthe manual,最后一个参数的类型应该是 IStream **。但是,代码片段将 wil::com_ptr<IStream> * 而不是 IStream ** 传递给函数。我想知道它是如何工作的。 wil::com_ptr<IStream> 是否重载运算符 &(又名“地址”)?

对了,我找不到wil::com_ptr的联机手册。和winrt::com_ptr struct template (C++/WinRT)一样吗?谢谢。

Windows Implementation Libraries (WIL) has its documentation published through its repository's wiki. The wil::com_ptr_t class template1 is described on the WinRT and COM wrappers 页面。

Object management methods 部分列出了三个 class 成员,它们允许客户端获取存储的接口指针的地址:

  • T** addressof()
    Returns the address of the internal pointer without releasing the current COM object. Do not use this for _Out_ parameters2 because it will leak the current COM object. For _Out_ parameters, use the & operator, which releases the current COM object before returning the address.
  • T** put()
    Releases the current COM object and returns the address of the internal pointer. Use this method when passing the com_ptr_t as a _Out_ parameter.
  • T** operator&()
    Same as put().

所以回答字面的问题:是的,wil::com_ptr_t does overload operator&() 到 return 做一些内务处理后的内部接口指针的地址。

wil::com_ptr_twinrt::com_ptr class template3, part of the C++/WinRT library. Neither of them are related to ATL's CComPtr or Visual Studio's _com_ptr_t 无关。这是四个官方实现,虽然它们都有相同的目标,即自动化 COM 对象的生命周期管理,但它们在实现上略有不同,结果令人惊讶4.

区别在于以下几个方面:

  • 带有接口指针参数的构造函数

    实现可以选择是承担传入接口指针的所有权,还是模型共享所有权让调用者负责 Release()-ing 传入接口指针。

  • 接受接口指针的赋值运算符

    与上面关于传入指针的内容相同,增加了必须处理实例已经持有接口指针的情况。实现可以:

    • 静默删除当前持有的接口指针(这是一个错误并不意味着你不会看到它)
    • 在分配传入接口指针之前静默Release()当前接口
    • 如果实例持有接口指针,则抛出异常
  • 正在检索原始接口指针的地址

    类似于上面的赋值,智能指针实例已经持有接口的情况需要这样或那样处理:

    • 静默删除存储的接口(例如addressof()
    • 静默Release()当前界面(例如put()
    • 如果存储的指针不是 nullptr
    • ,则抛出异常

如果您决定使用 COM 智能指针实现,请确保您牢牢掌握其语义。根据所使用的库,相同的 C++ 代码块可能会有不同的行为。


1 wil::com_ptrwil::com_ptr_talias templateerr_policy 模板参数设置为err_exception_policy.

2 即使 ppstm 被标记为 [=12=,问题中的代码片段也可以安全地通过 stream.addressof() ] 范围。我猜作者使用 operator&() 来代替一致性、可读性和可维护性。

3 虽然 WIL 和 C++/WinRT 是独立的库,但它们可以令人惊讶地互操作 little effort.

4 We're using a smart pointer, so we can't possibly be the source of the leak