如何用new分配一块内存?

Posted

技术标签:

【中文标题】如何用new分配一块内存?【英文标题】:how do I allocate one block of memory with new? 【发布时间】:2013-05-09 11:35:04 【问题描述】:

我有一个使用 new 动态分配的二维数组。

问题是我想将内存分配为一个连接块而不是分开的块以提高处理速度。

有谁知道是否可以使用 new 执行此操作,还是我必须使用 malloc?

这是我的代码:

A = new double*[m];
    for (int i=0;i<m;i++)
    
        A[i]= new double[n];
    

此代码导致分段错误

phi = new double**[xlength];
phi[0] = new double*[xlength*ylength];
phi[0][0] = new double[xlength*ylength*tlength];
for (int i=0;i<xlength;i++)

    for (int j=0;j<ylength;j++)
    
        phi[i][j] = phi[0][0] + (ylength*i+j)*tlength;
    
    phi[i] = phi[0] + ylength*i;

【问题讨论】:

考虑用它创建一个Matrix 类,用一维数组表示二维操作。 ***.com/questions/1719607/… 看看这个。 @bill,这没有回答我的问题,但感谢您的链接。 @Mechy 我知道这不是完全匹配,但我想你会感兴趣....因为它有点相关。 为什么不使用标准的容器类? 【参考方案1】:

好的,如果任务是维护单个内存块,但保持 [][] 的寻址方式,我会尝试使用类的一些技巧。第一个是内部代理:

class CoordProxy

private:
    int coordX;
    int arrayWidth;
    int * dataArray;

public:
    CoordProxy(int * newArray, int newArrayWidth, int newCoordX)
    
        coordX = newCoordX;
        arrayWidth = newArrayWidth;
        dataArray = newArray;
    

    int & operator [](int newCoordY)
    
        return (dataArray[newCoordY * arrayWidth + coordX]);
    
;

class CoordsWrapper

private:
    int * dataArray;
    int width;
    int height;

public:
    CoordsWrapper(int * newArray, int newWidth, int newHeight)
    
        dataArray = newArray;
        width = newWidth;
        height = newHeight;
    

    CoordProxy operator[] (int coordX)
    
        return CoordProxy(dataArray, width, coordX);
    
;

int main(int argc, char * argv[])

    int * a = new int[4 * 4];
    ZeroMemory(a, 4 * 4 * sizeof(int));

    CoordsWrapper w(a, 4, 4);

    w[0][0] = 10;
    w[0][1] = 20;
    w[3][3] = 30;

    std::for_each(&a[0], &a[4 * 4], [](int x)  printf("%d ", x); );

    delete[] a;

请注意,这不是节省时间,而是非常节省内存:比原始类多使用 4 个整数和 2 个指针。

还有更好更快的解决方案,但您必须放弃 [][] 表示法,转而使用 (,) 表示法:

class CoordsWrapper2

private:
    int * data;
    int width;
    int height;

public:
    CoordsWrapper2(int * newData, int newWidth, int newHeight)
    
        data = newData;
        width = newWidth;
        height = newHeight;
    

    inline int & Data(int x, int y)
    
        return data[y * width + x];
    
;

int main(int argc, char * argv[])

    int * a = new int[4 * 4];
    ZeroMemory(a, 4 * 4 * sizeof(int));

    CoordsWrapper2 w(a, 4, 4);

    w.Data(0, 0) = 10;
    w.Data(0, 1) = 20;
    w.Data(3, 3) = 30;

    std::for_each(&a[0], &a[4 * 4], [](int x)  printf("%d ", x); );

    delete[] a;

注意 inline 指令。它建议编译器替换实际源代码的方法调用,这使其速度更快。此解决方案的内存效率更高,并且与经典索引相比,时间效率略低或相同。

【讨论】:

【参考方案2】:

您可以分配一个大块并适当地使用它,如下所示:

double* A = new double[m*n];
for (int i=0; i<m; i++) 
    for (int j=0; j<n; j++) 
        A[i*n+j] = <my_value>;
    

您可以使用malloc,而不是使用new - 没有太大区别,只是new 必须与delete 一起发布,而malloc()free() 一起发布。

更新1: 您可以按如下方式创建“真实”二维数组:

double** A = new double*[m];
double*  B = new double[m*n];
for (int i=0; i<m; i++) 
    A[i] = B + n*i;

for (int i=0; i<m; i++) 
    for (int j=0; j<n; j++) 
        A[i][j] = <my_value>;
    

请务必在最后同时释放AB

UPDATE2

根据大众的要求,这是创建“真实”3 维数组的方法(尺寸为 m x n x o):

double*** A = new double**[m];
double**  B = new double*[m*n];
double*   C = new double[m*n*o];
for (int i=0; i<m; i++) 
    for (int j=0; j<n; j++) 
        B[n*i+j] = C + (n*i+j)*o;
    
    A[i] = B + n*i;

for (int i=0; i<m; i++) 
    for (int j=0; j<n; j++) 
        for (int k=0; k<o; k++) 
            A[i][j][k] = <my_value>;
        
    

这使用了两个相对较小的“索引”数组AB,以及数据数组C。像往常一样,这三个都应该在使用后释放。

将其扩展到更多维度作为练习留给读者。

【讨论】:

这是制作一维数组的好方法,但如果我不想展平我的数组,是否可以像你一样用 new 制作一个大的连续内存块使用 malloc? @Mechy,如果我疯了,请不要引用我的话,但如果你 new[] 增加 20 ints 的空间,你也许可以摆脱治疗像int[4][5]int[5][4] 一样指向它的指针。我不确定这是否允许。在任何情况下,将其封装在 Matrix 类中会更干净。您可以只说mat(i,j),但在内部让它成为一维连续块。 我不确定我是否完全理解。我认为您通过将 A 的内存地址更改为 B 的内存的前 m 个地址,以某种方式使 B 和 A 重叠,对吗?没有指针你是怎么做到的?此外,这是否会从 A 中创建 m 块“浪费空间”内存? A 是相对较小的指针数组,它们指向大 B。唯一浪费的空间是A本身,但是很小 @Mechy:是的,由于内存堆维护,您的代码会产生大量开销。即使使用 3d 或 4d 数组的 2 级和 3 级索引,这种方法也应该更有效。【参考方案3】:

你可以用malloc 做任何你不能用new 做的事情(尽管反过来不成立)。但是,如果您已经在单独的块中分配了内存,则必须分配新的(连续的)内存才能获得连接的块(使用mallocnew)。您显示的代码分配 m 非连续 n 大小的块。要从中获取具有连续内存的数组,您需要

int MN = m*n;
B = new double[MN];
for (int i=0; i<MN; ++i)
   B[i] = A[ i/N ] [ i%N ];

【讨论】:

这是否意味着它已经是一大块内存了?我认为这东西会将条带分配在不同的位置。例如 AStrip B 在这里而不是 A 旁边。 我该如何解决这个问题?我不希望它参差不齐。 @Mechy 要获得一个连续的块,您只需分配一个包含 MxN 元素的一维数组,然后确保在数组中,数据是逐行(主要行)或逐列布局的-column (column-major),你的选择。

以上是关于如何用new分配一块内存?的主要内容,如果未能解决你的问题,请参考以下文章

TLAB?深入了解JVM是如何用它优化内存分配的

C++如何用new动态开辟一个一维字符数组

如何知道分配给定内存块的内容? [关闭]

new delete和mallocfree的解析及区别

malloc内存分配

new 和 malloc 的区别 及使用