2017-02-27 79 views
1

我想使用標準C++庫的智能指針與使用MS COM大部分其功能的庫智能指針(我必須說,我不是很精通與COM)。所以,我有我的unique_ptr使用STL與COM接口

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++嗎?

+5

微軟提供了一些智能指針類與COM指針時,有沒有你不希望使用其中的一個理由嗎?這似乎是對不存在的問題的解決方案。 –

+4

我會推薦使用COM的CComPtr。類似的問題已經在SO - [看到這個問題](http://stackoverflow.com/questions/21820301/using-stdunique-ptr-for-managing-com-objects) – mpiatek

+0

謝謝!對不起沒有意識到CComPtr。應該看看那個。剛開始使用COM ... – Luca

回答

2

事情是這樣的:

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); 

這裏有一個小的幹違規 - 已在每臺你這樣做時,重複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 
} 

我們再重寫的獲取接口函數:

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); 

有很多方法的類型有關聯指導,包括特質類。基於ADL的查找函數和變量模板只是一種方法。

未經測試的代碼。

+1

我結束了使用'CComPtr',但這是很好的知道! – Luca