CArray 使用不当会产生内存碎片,应先调用SetSize(),MSDN和网友都这么说,但具体怎么用还不是太清楚,先看代码:
// 1. 声明arr1后直接加
CArray<int> arr1;
arr1.Add( 1 );
TRACE( "1, 0x%x, ", &arr1[0] );
arr1.Add( 2 );
TRACE( "0x%x, %2i\r\n", &arr1[0], arr1.GetCount() ); // 显示第一个元素的地址变化
// 2. 声明后设置大小
CArray<int> arr2;
arr2.SetSize(2);
arr2.SetAt( 0, 1 );
TRACE( "2, 0x%x, ", &arr2[0] );
arr2.SetAt( 1, 2 );
TRACE( "0x%x, %2i\r\n", &arr2[0], arr2.GetCount() ); // 显示第一个元素的地址变化
// 3. 声明后设置预留大小
CArray<int> arr3;
arr3.SetSize( 0, 80 );
arr3.Add( 1 );
TRACE( "3, 0x%x, ", &arr3[0] );
for( int i = 0; i < 79; i++ )
arr3.Add( 2 );
TRACE( "0x%x, %2i\r\n", &arr3[0], arr3.GetCount() ); // 显示第一个元素的地址变化
运行结果:
1, 0x2bcf58, 0x2bcf98, 2
2, 0x2b9e78, 0x2b9e78, 2
3, 0x2b9ec0, 0x2b9ec0, 80
从以上结果看出,第一种方法未用SetSize是错的,执行arr1.Add( 2 )时会重新给第一项分配内存,内存地址变了(0x2bcf58, 0x2bcf98),第二、三种方法正确,添加元素时,不重新分配内存,内存地址不变。
说明:
void SetSize(
INT_PTR nNewSize,
INT_PTR nGrowBy = -1
);
nNewSize 分配数组元素,用SetAt方法初始化元素。
nGrowBy 预留一定空间,GetSize方法取不到这一部分,用Add方法加元素。
总结:
使用数组前先用SetSize分配空间。
如果已知数组大小,用SetSize(50)方法分配内存,再用SetAt方法初始化。
如果不确定数组大小,用SetSize(0, 100)方法预留内存,用Add方法初始化,第二个参数可以取大些,保证够用。
补充说明 2018/8/26
今天使用VS2017的堆分析工具,有了进一步的理解。
1. SetSize(INT_PTR nNewSize, INT_PTR nGrowBy)并不预分配内存,在第一次执行Add或InsertAt时分配nGrowBy内存,用完时再分配nGrowBy内存。
2. RemoveAll将销毁已经分配的内存,下次调用Add时再分配。如果频繁清除时请使用RemoveAt,不会重新分配内存。