When I used MFC's CArray in one of my projects, I found it's not very heap-friendly.
It does use a pre-allocated memory pool but it doesn't use it clearly. For example, it doesn't have a constructor
that allow us to explicitly declare the size of our pre-allocated memory pool.
Furthermore, I think MFC CArray
doesn't make clear between the actual memory pool size and the elements size of the array.
And if we really need to "pre-allocate", we has to make use of its grow-by variable, which is unclear and
How to use
Include the two files NewBValArray.h and NewBConfig.h in your project
Declare a variable:
rgMyArray will pre-allocate a memory pool of 1000
NOTE: rgMyArray is still a blank array, i.e
rgMyArray.GetSize() = 0; as
long as you don't "add" items to it through
Otherwise, it can be used the same as MFC's CArray, i.e you can safely
replace all CArray with NewBArray.
Why don't I use MFC CArray?
After my posting, many ask me why I didn't use MFC's CArray?
I do know that MFC CArray can pre-allocate memory. But it really doesn't work as I expect.
What do I expect? I'd like to separate the holder (memory) and the meaning of array elements.
That means I'll allocate a big chunk of memory to hold the elements' data. This memory should be
allocated in the array's ctor and delete at array's dtor. During its lifetime, this part of memory
shouldn't be changed
Now let's dive into the MFC CArray source code. It's contains 4 variables:
TYPE* m_pData; int m_nSize; int m_nMaxSize; int m_nGrowBy;
Now, let see how can we force CArray to pre-allocate memory by
SetSize(int nNewSize, int nGrowBy).
nNewSise is the new desired size.
nGrowBy I'll explain later. Then assume that we have
What if I do this:
Now I expect that rgMFCArray has 1000 pre-allocated spaces for
MyClass, means I can Add to it 1000
MyClass variables. But actually
rgMFCArray now contains 1000
MyClass "default" variables and
if I call
rgMFCArray.Add(...) then the
m_pData will need to reallocate to a 1001
MyClass space :
not what I expect.
Again, what if I do this:
Now I make use of the grow-by stuff. At this time
rgMFCArray will assign its
m_nGrowBy = 1000.
That's all! No allocation of memory. So if you do
rgMFCArray, you'll get ASSERT false.
Then what if:
Yeah, this time it's worked. Now
CArray will allocate a memory chunk of size
So if I really like to make use of pre-allocate memory on MFC's
CArray, I have to use its
More! MFC's Array doesn't provide you any method to "remove" all
CArray elements or change its memory
You can ask me about
CArray::RemoveAll(). This method will remove all array elements plus deallocate its
But really,we can remove all elements of MFC CArray with a long statement
for (int i = rgMFCArray.GetCount() - 1; i >= 0 ; i --)
Again, it make me confused and uneasy.
So that's why I rewrite my own array class by just "hacking" MFC's CArray source, cause really MFC CArray is still
a good boy, especially its making use of placement new and delete.
In my new class, I explicitly separate
m_nSize (number of elements) and
m_nMaxSize (the size of
pre-allocated memory pool). I added a ctor that has one parameter to declare the size of pre-allocated memory, and
this memory I can take from my own allocator as in many projects. And the method
RemoveAll() just effectively
"removes" the elements, i.e calls their dtor but leaves the memory pool untouched. This memory pool will be cleaned
at NewBArray's dtor. Moreover, I still keep the ability to "grow" the memory pool to a larger one if the user adds
more elements the array capacity. But this action shouldn't happen because it makes the heap fragment and cause
memory allocation, and copy overhead.
This code is written by Nguyen Binh. I greatly appreciate any feedback.