【问题标题】:using STL smart pointers with COM interfaces使用带有 COM 接口的 STL 智能指针
【发布时间】:2017-07-18 05:29:03
【问题描述】:

我正在尝试将标准 C++ 库智能指针与一个使用 MS COM 来实现其大部分功能的库一起使用(我必须说我并不精通 COM)。所以,我的unique_ptr 有以下自定义删除器

struct COMDeleter {
    template<typename T> void operator()(T* ptr) {
        if (ptr) ptr->Release();
    }
};

在示例代码中,我们有类似的内容:

class MyClass
{
public:
    MyClass(IDeckLink * device) 
      : m_deckLink(device)
    {            
    }  

    MyClass::~MyClass()
    {
        if (m_deckLink != NULL)
        {
            m_deckLink->Release();
            m_deckLink = NULL;
        }
    } 

    IDeckLink * m_deckLink;
};

这可以替换为:

class MyClass
{
public:
    MyClass(IDeckLink * device) 
    {  
        m_deckLink.reset(device);
    }   
    std::unique_ptr<IDeckLink, COMDeleter>  m_deckLink;
};

现在,我有另一个名为 IDeckLinkInput 的接口,我想用类似的方式包装它,但它的初始化方式不同,如下所示:

IDeckLinkInput* m_deckLinkInput = NULL;
if (m_deckLink->QueryInterface(IID_IDeckLinkInput, (void**) &m_deckLinkInput) != S_OK)
        return false;

所以,如果我有这样的智能指针:

std::unique_ptr<IDeckLinkInput, COMDeleter> m_deckLinkInput(nullptr);

我不确定如何将它与上述初始化功能一起使用?它甚至可以完成还是我应该坚持使用旧式 C++?

【问题讨论】:

  • Microsoft 提供了几个用于处理 COM 指针的智能指针类,您是否有不想使用其中一个的原因?这似乎是一个不存在的问题的解决方案。
  • 我建议将CComPtr 用于 COM。类似的问题已经在 SO - see this question
  • 吹毛求疵:智能指针不是 STL 的一部分,无论是原始 STL 还是标准库采用。
  • @chris 很多人使用 STL 来引用标准库中基于模板的部分。这不是正确的用法,但它非常普遍。请参阅stackoverflow.com/questions/5205491/… 了解整个混乱情况。

标签: c++ pointers com


【解决方案1】:

类似这样的:

template<class U, class T>
std::unique_ptr<U, COMDeleter>
upComInterface( GUID guid, T const& src ) {
  if (!src) return {};
  T* r = nullptr;
  if (src->QueryInterface( guid, (void**)&r) != S_OK)
    return {};
  return {r, {}};
}

那么我们:

auto deckLink = upComInterface<IDeckLinkInput>( IID_IDeckLinkInput, deckLink );

这里有一个轻微的 DRY 违规 - 每次执行此操作时都必须重复 IDeckLinkInputIID_IDeckLinkInput 之间的链接,并且错误会导致未定义的行为。

我们可以通过多种机制解决此问题。就个人而言,我会选择标签调度类型:

namespace MyComHelpers {
  template<class T> struct com_tag_t {using type=T; constexpr com_tag_t(){};};
  template<class T> constexpr com_tag_t<T> com_tag{};

  template<class T>
  constexpr void get_com_guid( com_tag_t<T> ) = delete; // overload this for your particular types

  template<class T>
  constexpr GUID interface_guid = get_com_guid( com_tag<T> );
}

现在我们可以将类型与 guid 关联起来。在IDeckLinkInput 的命名空间中执行以下操作:

constexpr GUID get_com_guid( MyComHelpers::com_tag_t<IDeckLinkInput> ) {
  // constexpr code that returns the GUID
}

然后我们重写get接口函数:

std::unique_ptr<U, COMDeleter>
com_cast( T const& src ) {
  if (!src) return {};
  T* r = nullptr;
  if (src->QueryInterface( MyComHelpers::interface_guid<T>, (void**)&r) != S_OK)
    return {};
  return {r, {}};
}

然后使用变成:

auto declLink = com_cast<IDeckLinkInput>(m_deckLinkInput);

有很多方法可以将类型与 guid 相关联,包括特征类。 constexpr 基于 ADL 的查找函数和变量模板只是其中一种方式。

代码未经测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-01
    相关资源
    最近更新 更多