【问题标题】:Using std::unique_ptr for managing COM objects使用 std::unique_ptr 管理 COM 对象
【发布时间】:2014-03-16 05:32:23
【问题描述】:

我正在尝试使用智能指针在我的类中保存 COM 对象,同时避免使用 ComPtr。是否可以为此目的使用 unique_ptr?

我对智能指针很陌生,到目前为止我有点困惑。请考虑以下简化代码:

class Texture
{
private:
    struct ComDeleter
    {
        operator() (IUnknown* p)
        {
            p.Release();
            delete p;
        }
    }

    ID3D11Texture* m_dumbTexture;
    std::unique_ptr<ID3D11Texture, ComDeleter> m_smartTexture;

public:
    ID3D11Texture* getDumbTexture() const { return m_dumbTexture; }
    ID3D11Texture* getSmartTexture() const { return m_smartTexture.get(); } // what to return here?
}

Texture::Texture() :
    dumbTexture  (NULL),
    smartTexture (nullptr)
{
}

Texture::init()
{
    D3DX11CreateTexture(&m_dumbTexture);
    D3DX11CreateTexture(&m_smartTexture.get());  // error: '&' requires r-value
}

所以我的问题是:getter 应该返回什么(原始指针或 unique_ptr 实例)以及如何将 unique_ptr 传递给创建资源的函数?

【问题讨论】:

  • 这属于重新发明轮子的范畴。使用 ComPtr 并继续前进。
  • p.Release(); delete p; 错误:COM 对象在最后一个 Release() 上自行销毁。
  • 所以不需要delete p?看来我一直在阅读一些错误的教程。
  • delete p非常错误。你有什么保证 COM 对象是用 C++ 的new 分配的,并且来自你的 C++ 库为你设置的同一个堆? (提示:绝对不是 DX 对象的情况)。 COM 对象管理自己的生命周期的一个主要原因是因为它们是唯一知道释放自己的正确方法的对象。
  • @PeterR 发现了这个问题并对其表示赞同,我想我的第一个想法是关于代码重用和可移植性。为了这些目的而避免使用特定于 Windows 的代码是有意义的。

标签: c++ c++11 com smart-pointers


【解决方案1】:

如果你真的想部分地重新发明轮子,你应该使用intrusive_ptr。通过调用AddRef()Release() 实现IUnknown 的递增/递减方法,它应该可以工作。

【讨论】:

    【解决方案2】:

    我正在尝试使用智能指针在我的类中保存 COM 对象,同时避免使用ComPtr

    解决方案是使用ComPtr。如果您正在使用 COM 对象,unique_ptr 不能很好地替代 ComPtr

    ComPtr 提供用于处理 COM 对象和IUnknown 的专用功能。例如,它内置了对安全接口查询的支持(通过As 成员函数)。它也可以在没有 out 参数的情况下使用,这在 COM 中很常见(通过 GetAddressOf 函数)。

    【讨论】:

    • 所以 a) 是否值得为单个智能指针包含整个 atlbase? b)如上:getter(原始指针或 CComPtr 实例)应该返回什么?c)我如何释放和重新创建 ComPtr 成员持有的资源(我在尝试 m_comptr-&gt;Release(); CreateResource(&amp;m_comptr); 时收到 'ATL::_NoAddRefReleaseOnCComPtr&lt;T&gt;::Release' : cannot access private member declared in class 'ATL::_NoAddRefReleaseOnCComPtr&lt;T&gt;'。跨度>
    • [a] 当然。或者在&lt;wrl/client.h&gt; 中使用较新的ComPtr。 [b] 这取决于用例以及调用者可能如何使用该类型的对象。从ComPtr&lt;T&gt; 开始。 [c] 你不能直接调用Release,你不应该:让ComPtr管理对AddRefRelease的调用。输出参数使用GetAddressOfReleaseAndGetAddressOf
    • 好的,很酷。还有一个问题:我可以使用std::vector&lt;ComPtr&lt;T&gt;&gt;吗?
    • 是的,至少在最新版本的 Visual C++ 中(当然是在 Visual C++ 2013 中)。
    猜你喜欢
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 2012-08-24
    • 1970-01-01
    相关资源
    最近更新 更多