动态分配数组
数组的大小不确定,数组的元素类型不确定,使用模板的方法创建数组,初始化数组, 删除数组。
遇到了分配三维数组内存不连续的问题,后续的memcpy操作会crash。因此需要创建内存连续的三维数组
动态分配二维数组
template<typename T>
T** allocate2DArray(int rows, int cols)
{
T** arr = new T * [rows];
for (int i = 0; i< rows; i++)
{
arr[i] = new T[cols];
}
return arr;
}
初始化二维数组
template<typename T>
void initialize2DArray(T** arr, int rows, int cols, T data)
{
for (int i = 0; i< rows; i++)
{
for (int j = 0; j < cols; j++)
{
arr[i][j] = static_cast<T>(data);
}
}
}
删除二维数组
template<typename T>
void delete2DArray(T** arr, int rows)
{
for (int i=0; i<rows; i++)
{
delete[] arr[i];
}
delete[] arr;
}
动态分配三维数组
在创建三维数组等相关的函数,参考二维数组得到如下内容:
// 分配内存空间
template<typename T, int N>
T*** allocate3DArray(int rows, int cols)
{
T*** arr = new T **[rows];
for (int i = 0; i< rows; i++)
{
arr[i] = new T* [cols];
for (int j = 0; j < cols; j++)
{
arr[i][j] = new T[N];
}
}
return arr;
}
// 初始化
template<typename T, int N>
void initialize3DArray(T***arr, int rows, int cols, float value)
{
for (int i = 0; i< rows; i++)
{
for (int j = 0; j< cols; j++)
{
for (int n = 0; n< N; n++)
{
arr[i][j][n] = static_cast<T>(value); // for example,假设一个固定的值
}
}
}
}
// 删除
template<typename T, int N>
void delete3DArray(T*** arr, int rows, int cols)
{
for (int i=0; i< rows; i++)
{
for (int j=0; j<cols; j++)
{
delete[] arr[i][j];
}
delete[] arr[i];
}
delete[] arr;
}
但是在create 3维数组时,内存分布上并不是连续的。
连续内存分配方式:
// 分配连续内存
template<typename T, int N>
T*** allocate3DArray(int rows, int cols)
{
T*** arr = new T **[rows];
T** data = new T * [rows * cols];
T* flatData = new T[rows * cols * N]; //一块连续内存
for (int i = 0; i< rows; i++)
{
arr[i] = data + i * cols; //连续的行
for (int j = 0; j < cols; j++)
{
arr[i][j] = flatData + (i * cols + j)*N; //偏移
}
}
return arr;
}
template<typename T, int N>
void initialize3DArray(T***arr, int rows, int cols, float value)
{
for (int i = 0; i< rows; i++)
{
for (int j = 0; j< cols; j++)
{
for (int n = 0; n< N; n++)
{
arr[i][j][n] = static_cast<T>(value); // 1.0
}
}
}
}
// 删除
template<typename T, int N>
void delete3DArray(T*** arr, int rows, int cols)
{
// False way
//delete[] arr_[0][0];
//delete[] arr_[0];
//delete[] arr_;
// Correct way
delete[] flatData; // delete flattened 3D data array
delete[] arr_; // delete the array of pointers
// no need to delete each inner array
}
不连续的原因分析
在一开始的版本中,三维中的每一位,都是独立分配的。 它首先为行指针数组分配内存(arr), 然后对于每一行,它为cols指针数组(arr[i])分配内存。最后,对于2D数组中的每个元素(arr[i][j]),它为包含N个元素的数组分配内存。
在第二种方式中,引入了两个额外的间接层来实现连续内存布局。该函数为行指针数组(arr)分配内存。此外,它为rows* cols指针数组(data)和rows* cols * N元素数组(flatData)分配内存。
arr指针被指定指向数据数组中相应的行,以确保行存储的内存是连续的。然后,对于2D数组的每个元素(arr[i][j]),它计算flatData数组中的适当偏移量,以指向相应的内存位置。
在allocate2DArray函数的原始实现中,使用新的T[cols]将每一行分配为一个单独的数组,并且指向这些行的指针存储在一个连续的内存块(arr)中。因此,行的内存保证是连续的。
析构函数的原则
- Delete the flattened data array first, since it owns the underlying memory
- Then delete the top level array of pointers
- No need to loop and delete each inner array, since they don’t own any memory