A customer had a problem deleting a WIC pixel buffer. Fortunately, they were able to reduce it to a few lines of code.
// Code in italics is wrong. UINT sourceBufferSize = 0; BYTE* sourceBuffer = nullptr; // The next line succeeds. bitmapLock->GetDataPointer(&sourceBufferSize, &sourceBuffer)); // Omitted code that performs some tasks on the pixels if (sourceBuffer != nullptr) { delete sourceBuffer; }
"The problem is that when we try to delete the
sourceBuffer
, we get an error from the
Visual C++ Debug Library:
Debug Assertion Failed!
Program: Contoso.exe
File: dbgdel.cpp
Line: 52
Expression: _BLOCK_
For more information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts.
"We're not sure what the problem is.
Does this mean that we don't need to delete the pixel buffer,
and it will be automatically deleted when we release the
IWIC
?
I tried leaving the buffer alone,
and it doesn't seem to result in a memory leak,
but we want to be sure that's the right thing."
The answer is obvious if you are an operating system person:
The operating system doesn't know anything about
your language runtime's memory allocation strategy.
It doesn't try to guess
what version of the C++ runtime you're using,
and even if it tried to guess, what would it do when
faced with a C++ runtime from the future?
As far as the operating system is concerned,
the delete
operator is just some function
that is private to your program.
It could be called flubber
for all the
operating system knows.
How can the operating system know how to allocate memory
so it can be flubber
ed?
Anyway,
the deal is that the pointer you get back from
the GetDataPointer
method is
a pointer to memory that is not owned by you.
The lock gives you access to the memory,
but all you can do is access the memory.
You cannot free it because it was never yours.
The same logic applies to GDI bitmaps.
When you create a GDI bitmap, you get an HBITMAP
,
which represents the bitmap.
You can ask GDI to tell you where it put the bitmap pixels
by calling GetObject
:
a pointer to the bits will be returned in the
bmBits
member,
and you can use that pointer to read or write the
pixels of the bitmap.
But you can't free the memory.
The memory belongs to the HBITMAP
.
The IWICBitmap
works in a similar way.
When you create a WIC bitmap, it allocates some memory
to hold the pixels,
and that memory belongs to the bitmap.
You can call IWICBitmap::
,
to get an object represented by the
IWICBitmapLock
interface.
From the lock object, you can ask for a pointer to
the memory that holds the pixels,
at which point you can read or write the pixels.
That pointer is valid only for the duration of the
lock.
After you release the lock, the WIC bitmap is permitted
to move the memory to somewhere else.
(For example, this might happen as part of atlas compaction.)
This is all spelled out and even demonstrated in the
sample code that accompanies
the IWICBitmapLock::
method.