【问题标题】:RAII with array of COM objects带有 COM 对象数组的 RAII
【发布时间】:2013-09-11 12:47:43
【问题描述】:

问题:

在 COM 中,您偶尔会发现带有 this 等签名的函数:

HRESULT STDMETHODCALLTYPE GetColorContexts( 
        UINT cCount,
        IWICColorContext **ppIColorContexts,
        UINT *pcActualCount)

这给我带来的问题是ppIColorContexts 必须是IWICColorContext *initialized 数组。我尝试引用ATL::CComPtr<IWICColorContext>Vector 的第一个元素,但没有这样的运气,它不会触发() 运算符,因此它会抱怨类型不匹配。

尝试的解决方案:

  • vector<ATL::CComPtr<IWICColorContext>> 由于类型不匹配而失败,如 cmets 中所述,这还有其他问题,因为 CComPtr 重载 operator & 会破坏 STL 容器。似乎这是 fixed in C++11 并包含在VC2010中的STL
  • BOOST_SCOPE_EXIT_ALL 有效,但仍然意味着我正在手动管理 COM 对象的生命周期,这是我想摆脱的。

未尝试的解决方案:

  • 自定义数据结构 - 如果没有更优雅的解决方案,这可能是我必须要做的,但至少它可以让我正确利用破坏语义。
  • 在此调用后附加CComPtr - 我不喜欢此解决方案,因为它给我留下了一段执行期,如果出现问题,资源可能不会被释放。
  • std::unique_ptr<IWICColorContext[]> 带有自定义删除器 - 我还没有完全探索这种可能性,但它可以确保 COM 对象总是被释放。

【问题讨论】:

  • 它想要一个数组,只需传递一个普通的旧数组。任何使用智能指针的包装都必须在调用之后完成。
  • 我想你想要这样的东西:vector<CAdapt<CComPtr<IWICColorContext> > > vec; GetColorContexts(vec.size(), &vec[0].m_T, ...);CComPtr 不能直接放入 STL 容器中,因为它重载了 operator&,这违反了容器要求。这就是 CAdapt 被发明的原因。
  • @HansPassant 我希望避免这种情况,但如果这是我必须要做的,那就是我必须要做的......我仍然希望避免new
  • @HansPassant 带有自定义删除器的std::unique_ptr<IWICColorContext[]> 怎么样?仍然不理想......但它应该总是被释放。
  • @IgorTandetnik 是 fixed in C++11 并且修复包含在 VC2010 的 TR1 版本中

标签: c++ com raii


【解决方案1】:

我会通过将原始指针向量传递给函数,然后复制到 CComPtr 的另一个向量来做到这一点。

std::vector<IWICColorContext *> vec(5, NULL);
UINT nActualCount = 0;
GetColorContexts(vec.size(), &vec[0], &nActualCount);
std::vector<CComPtr<IWICColorContext> > results(vec.begin(), vec.begin() + nActualCount);

唯一不幸的部分是CComPtr 构造函数执行AddRef,因此您必须在原始指针丢失之前对它们执行相应的Release

for (auto it = vec.begin(); it != vec.end(); ++it)
    if (*it != NULL)
        (*it)->Release();
vec.clear();

【讨论】:

  • 虽然这不是最有效的事情......我可以把它颠倒过来并从vector&lt;CComPtr&gt; 创建一个std::vector&lt;IWICColorContext*&gt; 这不会产生参考问题,因为无论如何,每个图像的上下文数量都很少。
【解决方案2】:

最终解决方案由 igor tandetnik 在上面的 cmets 中描述:

基本上在 VC2010+ 中,ATL::CComPtr 有一个 sizeof,它与它们所代表的指针相同(例如 sizeof(ATL::CComPtr&lt;IWICColorContext&gt;) == sizeof(IWICColorContext*)),据我所知,这是因为它们没有虚函数,因此不需要 vTable。然而,这非常危险,因为它依赖于编译器实现细节。因此以下工作:

std::vector<ATL::CComPtr<IWICColorContext> > > vec(5);
// CComPtrs are created and initialized here
GetColorContexts(vec.size(), &vec[0].m_T, ...);

Mark 提出了一个很好的观点,即上述解决方案完全依赖于编译器实现,这很危险。然而,在GetColorContexts 调用之后仅附加ATL::CComPtr 的解决方案也不令人满意,因为它不会是异常安全的。

最终我的解决方案(今天早上测试)是从vector&lt;CComPtr&lt;IWICColorContext&gt;&gt; 临时创建一个vector&lt;IWICColorContext*&gt;,这个临时vector 不会增加引用计数并允许我保持异常安全。

【讨论】:

  • 您在这里非常依赖 CComPtr 对象的内部结构。这很危险,特别是如果它有效(今天......)
  • @MarkRansom 我已经根据你的回答修正了我的答案
【解决方案3】:

我认为你需要这样的东西:

long lSize = 0;
ptr->GetColorContexts(cCount, NULL, &lSize);//return required amount of contexts
IWICColorContext** ppColorContexts = NULL;
ppColorContexts = new IWICColorContext*[lSize];
ptr->GetColorContexts(cCount, ppColorContexts, &lSize);
//use something to wrap received raw interfaces with CComPtr - 
//for example use for loop to pass them to new container,
//which stores CComPtr<IWICColorContext>

【讨论】:

    猜你喜欢
    • 2017-05-05
    • 2013-08-21
    • 1970-01-01
    • 2011-01-20
    • 2021-01-27
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    • 2020-08-19
    相关资源
    最近更新 更多