Search code examples
c++memory-leakscomatldirect2d

CComPtr and reference count


I am using objects of type CComPtr. But I am having some memory leak problems. In particular, I have the following code:

CComPtr<ID2D1Bitmap> bitmap = create_bitmap(bitmapSize);
auto n = count_ref((ID2D1Bitmap*)bitmap);

Where:

template<class Interface>
ULONG count_ref(Interface* pInterface) noexcept
{
    if (pInterface)
    {
        pInterface->AddRef();
        return pInterface->Release();
    }

    return 0;
}

And:

ID2D1Bitmap* create_bitmap(const D2D1_SIZE_U& size)
{
    ID2D1Bitmap* bitmap;
    CreateBitmap(&bitmap);

    return bitmap;
}

I was expecting a value of n equal to 1 but it is actually equal to 2. Why the reference count of my CComPtr is not 1?

Am I using my CComPtr object properly?

And when the process terminates I get the following memory leak:

An interface [072B1F50] was created but not released. Use 'dps 072B1F20' to view its allocation stack.
Object type: ID2D1Bitmap
    Device-dependent size: 1000 x 600
    Device-independent size: 1000.00 x 600.00
    Format: DXGI_FORMAT_B8G8R8A8_UNORM
    Alpha mode: D2D1_ALPHA_MODE_PREMULTIPLIED
    Outstanding reference count: 1

D2D DEBUG ERROR - Memory leaks detected.

Solution

  • With CComPtr you rarely need to use raw interface pointer types.

    You can make it this way, for example:

    CComPtr<ID2D1Bitmap> create_bitmap(const D2D1_SIZE_U& size)
    {
        CComPtr<ID2D1Bitmap> bitmap;
        CreateBitmap(&bitmap); // Declared as CreateBitmap(ID2D1Bitmap**);
        return bitmap;
    }
    
    CComPtr<ID2D1Bitmap> pBitmap = create_bitmap(...);
    ...
    

    CComPtr class will manage references accurately along the way you pass the pointers: local variable, return value, new local value. Optimizing compiler in Release builds also removes some of the excessive AddRef/Releases too, so you don't need to worry much about them.