使用带有 COM 接口的 STL 智能指针
using STL smart pointers with COM interfaces
我正在尝试将标准 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++?
像这样:
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 违规行为——每次执行此操作时都必须重复 IDeckLinkInput
和 IID_IDeckLinkInput
之间的 link,错误会导致未定义的行为.
我们可以通过多种机制解决这个问题。就个人而言,我会选择标签分发类型:
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 的查找函数和变量模板只是一种方式。
代码未经测试。
我正在尝试将标准 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++?
像这样:
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 违规行为——每次执行此操作时都必须重复 IDeckLinkInput
和 IID_IDeckLinkInput
之间的 link,错误会导致未定义的行为.
我们可以通过多种机制解决这个问题。就个人而言,我会选择标签分发类型:
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 的查找函数和变量模板只是一种方式。
代码未经测试。