删除动态数组的正确方法是什么?
What is the proper way to delete a dynamic array?
我动态创建了一个 3D 数组 t
(t
的类型是 int***
)。现在我正在尝试删除它。
我遇到了 2 个建议:
一种是简单地做
delete[] t;
显然,它会删除所有内容。
另一种是做类似
的事情
for(int i=0;i<3;i++)
{
for(int j=0;j<t1[i];j++)
{
delete[] t[i][j];//delete all 1D array
}
delete[] t[i];//delete all 2D array
}
delete[] t;//delete the 3D array
(t1
存储 t[i]
的大小,t2
存储 t[i][j]
的大小)
最好的方法是什么?
正如@aschepler 在评论中提到的,这取决于内存最初是如何分配的。我假设您可能是这样分配内存的:
int*** t = new int**[dim1];
for (int i = 0; i < dim1; i++) {
t[i] = new int*[dim2];
for (int j = 0; j < dim2; j++) {
t[i][j] = new int[dim3];
}
}
如果你以这种方式分配内存,那么内存看起来像这样:
[ 0 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
+---> [ 1 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
| [ 2 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
|
t ---> [ 0 ] [ 1 ]
|
| [ 0 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
+---> [ 1 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 2 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
现在,假设您只写
delete[] t;
如果您这样做,那么内存将如下所示:
[ 0 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 1 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 2 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
t ---> xxx
[ 0 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 1 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 2 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
换句话说,您回收了其中一个数组,但泄漏了大部分内存。糟糕!
另一方面,如果您使用删除代码的 for 循环版本,您最终会回收所有内存,因为您已经遍历了所有指针并释放了分配的每个数组。
一般来说,每个分配都应该有一个匹配的释放,所以如果你多次调用 new[]
,你需要调用 delete[]
相同的次数。
正如一些评论所指出的,管理 3D 阵列可能有比使用 int ***
更好的方法。 C++的大趋势是尽可能使用对象来自动管理内存。考虑研究 Boost multi_array
类型,或者考虑围绕 std::vector
编写一个包装器,以行优先顺序存储条目。
正确取消分配内存与分配内存一样重要。
我们在堆上创建多维数组时应该像在删除它时一样谨慎:
#include <iostream>
using std::cout;
using std::endl;
int main()
{
int*** ptrInt = new int**[3];
for(int i(0); i < 3; i++)
ptrInt[i] = new int*[3];
for(int i = 0; i < 3; i++)
{
for(int j(0); j < 3; j++)
ptrInt[i][j] = new int[3];
}
for(int i = 0; i < 3; i++)
{
for(int j(0); j < 3; j++)
for(int k(0); k < 3; k++)
ptrInt[i][j][k] = k;
}
for(int i = 0; i < 3; i++)
{
for(int j(0); j < 3; j++)
for(int k(0); k < 3; k++)
cout << "ptrInt[" << i << "][" << j << "][" << k << "]: " << ptrInt[i][j][k] << endl;
}
// now freeing memory:
for(int i = 0; i < 3; i++)
{
for(int j(0); j < 3; j++)
delete[] ptrInt[i][j];
delete[] ptrInt[i];
}
delete[] ptrInt;
ptrInt = NULL; // if we call delete again on a null pointer it's ok
cout << endl;
return 0;
}
我动态创建了一个 3D 数组 t
(t
的类型是 int***
)。现在我正在尝试删除它。
我遇到了 2 个建议: 一种是简单地做
delete[] t;
显然,它会删除所有内容。
另一种是做类似
的事情for(int i=0;i<3;i++)
{
for(int j=0;j<t1[i];j++)
{
delete[] t[i][j];//delete all 1D array
}
delete[] t[i];//delete all 2D array
}
delete[] t;//delete the 3D array
(t1
存储 t[i]
的大小,t2
存储 t[i][j]
的大小)
最好的方法是什么?
正如@aschepler 在评论中提到的,这取决于内存最初是如何分配的。我假设您可能是这样分配内存的:
int*** t = new int**[dim1];
for (int i = 0; i < dim1; i++) {
t[i] = new int*[dim2];
for (int j = 0; j < dim2; j++) {
t[i][j] = new int[dim3];
}
}
如果你以这种方式分配内存,那么内存看起来像这样:
[ 0 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
+---> [ 1 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
| [ 2 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
|
t ---> [ 0 ] [ 1 ]
|
| [ 0 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
+---> [ 1 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 2 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
现在,假设您只写
delete[] t;
如果您这样做,那么内存将如下所示:
[ 0 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 1 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 2 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
t ---> xxx
[ 0 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 1 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
[ 2 ] --> [ 0 ][ 1 ][ 2 ][ 3 ]
换句话说,您回收了其中一个数组,但泄漏了大部分内存。糟糕!
另一方面,如果您使用删除代码的 for 循环版本,您最终会回收所有内存,因为您已经遍历了所有指针并释放了分配的每个数组。
一般来说,每个分配都应该有一个匹配的释放,所以如果你多次调用 new[]
,你需要调用 delete[]
相同的次数。
正如一些评论所指出的,管理 3D 阵列可能有比使用 int ***
更好的方法。 C++的大趋势是尽可能使用对象来自动管理内存。考虑研究 Boost multi_array
类型,或者考虑围绕 std::vector
编写一个包装器,以行优先顺序存储条目。
正确取消分配内存与分配内存一样重要。 我们在堆上创建多维数组时应该像在删除它时一样谨慎:
#include <iostream>
using std::cout;
using std::endl;
int main()
{
int*** ptrInt = new int**[3];
for(int i(0); i < 3; i++)
ptrInt[i] = new int*[3];
for(int i = 0; i < 3; i++)
{
for(int j(0); j < 3; j++)
ptrInt[i][j] = new int[3];
}
for(int i = 0; i < 3; i++)
{
for(int j(0); j < 3; j++)
for(int k(0); k < 3; k++)
ptrInt[i][j][k] = k;
}
for(int i = 0; i < 3; i++)
{
for(int j(0); j < 3; j++)
for(int k(0); k < 3; k++)
cout << "ptrInt[" << i << "][" << j << "][" << k << "]: " << ptrInt[i][j][k] << endl;
}
// now freeing memory:
for(int i = 0; i < 3; i++)
{
for(int j(0); j < 3; j++)
delete[] ptrInt[i][j];
delete[] ptrInt[i];
}
delete[] ptrInt;
ptrInt = NULL; // if we call delete again on a null pointer it's ok
cout << endl;
return 0;
}