RAII与COM对象数组

时间:2013-09-11 12:47:43

标签: c++ com raii

问题:

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

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

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

尝试解决方案:

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

未尝试的解决方案:

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

3 个答案:

答案 0 :(得分:2)

我会通过将原始指针向量传递给函数,然后复制到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();

答案 1 :(得分:1)

最终解决方案由igor tandetnik在上述评论中描述:

基本上在VC2010 + ATL::CComPtr中有sizeof与它们所代表的指针相同(例如sizeof(ATL::CComPtr<IWICColorContext>) == sizeof(IWICColorContext*)),我最好能说明这是因为它们没有虚函数因此不需要vTable。然而,这是 高度危险 ,因为它依赖于编译器实现细节。因此,以下工作:

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

<击>

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

最终我的解决方案(今天早上测试)是暂时从vector<IWICColorContext*> vector<CComPtr<IWICColorContext>>创建vector这个临时{{1}}不会增加引用计数并允许我维护异常安全。< / p>

答案 2 :(得分:-1)

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

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>