C++ C++;3d阵列-动态内存分配在一行中对齐
我有一个很奇怪的问题,可能没有实际用途,但答案让我很困扰。今天我试着用下面的代码来处理数组以及它们在内存中的分配:(编译器Xcode 4 btw,4字节整数)C++ C++;3d阵列-动态内存分配在一行中对齐,c++,c,arrays,memory,allocation,C++,C,Arrays,Memory,Allocation,我有一个很奇怪的问题,可能没有实际用途,但答案让我很困扰。今天我试着用下面的代码来处理数组以及它们在内存中的分配:(编译器Xcode 4 btw,4字节整数) int***c; int size_x=0; int size_y=0; int size_z=0; cout size_x; cout size_y; cout size_z; c=新的整数**[大小x]; 对于(int i=0;i和 Dele[]。若要分配数组,最好直接使用向量;)每个新建[]都需要删除[]。非常感谢您的回答。有很多意
int***c;
int size_x=0;
int size_y=0;
int size_z=0;
cout size_x;
cout size_y;
cout size_z;
c=新的整数**[大小x];
对于(int i=0;i cout是的,这是正常的。内存是对齐的,顺便说一句,它只是不连续的,因为后续调用new
不能保证这一点。是的,您可以在单个连续缓冲区中分配整个三维数组:
int *A = new int[size_x * size_y * size_z];
或者,更安全
std::vector<int> A(size_x * size_y * size_z);
获取(i,j,k)
处的元素
这实际上是非常有用的,因为它给了你多维数组,开销小,保存和防止间接。而且,这种分配方案的错误处理要简单得多,这样你就不会有内存泄漏的风险。任何好的矩阵库都会以这种方式实现。对于C++,包括:
关于解除分配:是的,在当前方案中需要多次调用<代码>删除[]/COD>。< P> >问题不是你的内存不对齐……C++命令要求调用<代码>新< /COD>和<代码> NeX[]
是指它传回一个指针,指向与平台和请求对象大小正确对齐的连续内存
您的问题是,对new[]
的一次调用并不是为数组分配整个缓冲区,而是多次调用new[]
。因此,虽然每次调用new
都将返回对齐的连续内存,但对new[]的多次调用
不需要返回自己连续分配的内存缓冲区。例如,每次调用new[]
都会返回对齐的内存,但正如您所指出的,在new
返回的每个内存数组的开头都可能有“间隙”。这些“间隙”的原因是什么可能有多种原因,这实际上取决于底层操作系统如何为您的程序分配内存
如果不希望每个数组中都有任何“间隙”,则需要通过调用new
来分配整个缓冲区
最后,要回答您关于delete[]
的问题,是的,因为您没有通过对new[]
的一次调用来分配整个内存缓冲区,您不能通过对delete[]
的一次调用来删除数组。对new[]
的每次调用都必须与对delete[]的调用配对
因为这些是单独的内存分配。是的,这是正常的。
您可以逐行分配数据;唯一可以确定的是数据在每一行上都是连续的。因为这是标记为C的,所以这里还有一个C答案。因为C99多维数组可以非常有效地处理,即使大小是动态的:
double c[size_x][size_y][size_z];
这会在堆栈上连续分配矩阵。矩阵元素由c[i][j][k]
访问,编译器会为您执行所有索引算法。如果您担心这会导致这种情况,您可以使用它轻松调用malloc
:
double (*c)[size_y][size_z] = malloc(sizeof(double[size_x][size_y][size_z]));
下面是一个例程,它在连续内存空间中分配尺寸为N1 x N2 x N3的3D数组,同时允许您使用a[i][j][k]语法进行运算符访问。该数组是动态的,但连续的,因此它比向量方法和新[]调用循环有巨大的优势
template <class T> T ***Create3D(int N1, int N2, int N3)
{
T *** array = new T ** [N1];
array[0] = new T * [N1*N2];
array[0][0] = new T [N1*N2*N3];
int i,j,k;
for( i = 0; i < N1; i++) {
if (i < N1 -1 ) {
array[0][(i+1)*N2] = &(array[0][0][(i+1)*N3*N2]);
array[i+1] = &(array[0][(i+1)*N2]);
}
for( j = 0; j < N2; j++) {
if (j > 0) array[i][j] = array[i][j-1] + N3;
}
}
cout << endl;
return array;
};
template <class T> void Delete3D(T ***array) {
delete[] array[0][0];
delete[] array[0];
delete[] array;
};
我添加了一个C++标签。我是否应该删除C标签,或者你真的想要有一个C答案吗?Mon DealC++和C++在实现多维数组方面有很大的不同。这实际上是一个实际的使用,通过移除间接和帮助缓存。顺便说一句,而不是使用<代码> NeX[]/Calp>和<代码> Dele[]。若要分配数组,最好直接使用
向量
;)每个新建[]
都需要删除[]
。非常感谢您的回答。有很多意义,并为我清除了问题。。我现在写了上面的内容,我是如何删除内存的。它似乎工作正常。当我在使用相同的空间后分配内存时,不要在最后一行中执行delete[]m\u数组,m_array=NULL;
在最后一行中……逗号不会创建“序列点”根据C++的规范,因此取决于编译器是如何决定对操作进行排序的,当编译器决定反转操作并将<代码> null >代码>分配到MyLoad,然后调用<代码> Dele[]时,可能会导致巨大的内存泄漏。在nowNULL
指针上。你会想用分号分隔这两个单独的语句。第一个语句也更快吗?我可以想象,因为系统不需要如此频繁地跳转,对吗?@MarkusPfundstein:对于许多操作,是的。这就是我所说的引用位置。这也是等价的nt到上面larsman的答案,其中数组被分配为int*A=new int[N1*N2*N3]
,被访问为val=A[i*N2*N3+j*N3+k]
。但这里是指向指针的所有指针的bc,您可以使用val=array3d[i][j][k]
。要获得数组的等效int*
类型引用,可以执行int*A=array3d[0][0]
。
double c[size_x][size_y][size_z];
double (*c)[size_y][size_z] = malloc(sizeof(double[size_x][size_y][size_z]));
template <class T> T ***Create3D(int N1, int N2, int N3)
{
T *** array = new T ** [N1];
array[0] = new T * [N1*N2];
array[0][0] = new T [N1*N2*N3];
int i,j,k;
for( i = 0; i < N1; i++) {
if (i < N1 -1 ) {
array[0][(i+1)*N2] = &(array[0][0][(i+1)*N3*N2]);
array[i+1] = &(array[0][(i+1)*N2]);
}
for( j = 0; j < N2; j++) {
if (j > 0) array[i][j] = array[i][j-1] + N3;
}
}
cout << endl;
return array;
};
template <class T> void Delete3D(T ***array) {
delete[] array[0][0];
delete[] array[0];
delete[] array;
};
int *** array3d;
int N1=4, N2=3, N3=2;
int elementNumber = 0;
array3d = Create3D<int>(N1,N2,N3);
cout << "{" << endl;
for (i=0; i<N1; i++) {
cout << "{";
for (j=0; j<N2; j++) {
cout << "{";
for (k=0; k<N3; k++) {
array3d[i][j][k] = elementNumber++;
cout << setw(4) << array3d[i][j][k] << " ";
}
cout << "}";
}
cout << "}";
cout << endl ;
}
cout << "}" << endl;
Delete3D(array3d);
{
{{ 0 1 }{ 2 3 }{ 4 5 }}
{{ 6 7 }{ 8 9 }{ 10 11 }}
{{ 12 13 }{ 14 15 }{ 16 17 }}
{{ 18 19 }{ 20 21 }{ 22 23 }}
}