7

I'm trying to use smart pointers to hold COM objects in my class while avoiding ComPtr. Is it possible to use unique_ptr for this purpose?

I'm quite new to smart pointers and so far I'm a bit confused. Please consider the following simplified code:

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
}

So my problems are: what should the getter return (raw pointer or unique_ptr instance) and how can I pass the unique_ptr to function which creates the resource?

5
  • 3
    This falls into the re-inventing the wheel category. Use ComPtr and move on. Commented Feb 17, 2014 at 3:47
  • 3
    p.Release(); delete p; is wrong: COM objects destroy themselves on the last Release(). Commented Feb 17, 2014 at 4:15
  • So no delete p necessary? Looks like I've been reading some wrong tutorials. Commented Feb 17, 2014 at 4:18
  • 2
    delete p is very wrong. What guarantee do you have that the COM object was allocated with C++'s new, and out of the same heap that your C++ library sets up for you? (hint: definitely not the case for DX objects). A major reason why COM objects manage their own lifetimes is because they are the only ones that know the correct way to deallocate themselves. Commented Feb 20, 2014 at 3:52
  • @PeterR Have found this question and upvoted it, I suppose one of my first thoughts were about code reuse and portability. It would make sense to want to avoid Windows specific code for those purposes. Commented Aug 13, 2020 at 13:23

2 Answers 2

6

I'm trying to use smart pointers to hold COM objects in my class while avoiding ComPtr.

The solution is to use ComPtr. unique_ptr is a poor substitute for ComPtr if you're working with COM objects.

ComPtr provides specialized functionality for working with COM objects and IUnknown. For example, it has built in support for safe interface querying (via the As member function). It is also usable with out parameters, which are common in COM (via the GetAddressOf functions).

Sign up to request clarification or add additional context in comments.

4 Comments

So a) is it worth it to include the whole atlbase for a single smart pointer? b) As above: what should be returned by a getter (raw pointer or CComPtr instance? c) how can I release and recreate a resource held by ComPtr member (I'm getting 'ATL::_NoAddRefReleaseOnCComPtr<T>::Release' : cannot access private member declared in class 'ATL::_NoAddRefReleaseOnCComPtr<T>' when trying to m_comptr->Release(); CreateResource(&m_comptr);.
[a] Sure. Or use the newer ComPtr in <wrl/client.h>. [b] It depends on the use case and exactly how callers are likely to use objects of the type. Start with ComPtr<T>. [c] You cannot call Release directly, and you shouldn't: Let the ComPtr manage calls to AddRef and Release. Use GetAddressOf or ReleaseAndGetAddressOf for out parameters.
Ok, cool. Just one more question: can I use std::vector<ComPtr<T>>?
Yes, at least in recent versions of Visual C++ (certainly in Visual C++ 2013).
2

If you really want to partially reinvent the wheel, you should use intrusive_ptr. Implement the incrementation/decrementation methods for IUnknown with calling AddRef() and Release() and it should work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.