Reputation: 10499
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.
Upvotes: 2
Views: 2814
Reputation: 170489
There's a number of issues with this code.
Issue one is minor but it can lead to a lot of misunderstanding. AddRef()
and Release()
are not actually required to return any sensible values. So it's good they return the actual reference count but you cannot rely on this every time. So basically your count_ref()
function is naive and unreliable.
Now assuming that Release()
returns the real reference count it's clear that create_bitmap()
returns an object which already has it's reference count set to one. Then CComPtr
calls AddRef()
and reference count changes to 2. Then when CComPtr
goes out of scope its destructor calls Release()
and then there're no more pointers to the object and it gets leaked.
The solution to the later problem would be to use CComPtr::Attach()
to just take ownership of the object returned by create_bitmap()
without having AddRef()
called once again:
CComPtr<ID2D1Bitmap> bitmap;
bitmap.Attach(create_bitmap(bitmapSize));
that would make code work but it's not very clear and perhaps a bit harder to maintain than necessary. If you can afford changing create_bitmap()
signature then it'd be better to change it so that it returns CComPtr
as suggested in the other answer. This makes it clear that the caller must take ownership of the object to anyone seeing the function signature and there's no need to use separate calls to Attach()
.
Upvotes: 2
Reputation: 69687
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.
Upvotes: 5
Reputation: 37587
When you construct CComPtr from pointer it will share ownership of this pointer and increment reference count. To take ownership of pointer without incrementing reference count use CComPtr::Attach method.
CComPtr<ID2D1Bitmap> bitmap;
bitmap.Attach(create_bitmap(bitmapSize));
Upvotes: 4