how do I allocate one block of memory with new?

梦想与她 提交于 2019-11-28 06:02:24

问题


I have a two dimensional array that I've allocated dynamically using new.

The problem is I want to allocate the memory as one connected block instead of in separated pieces to increase processing speed.

Does anyone know if it's possible to do this with new, or do I have to use malloc?

Here's my code:

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

This code causes a segmentation fault

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;
}

回答1:


You can allocate one big block and use it appropriately, something like this:

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>;
    }
}

Instead of using new, you can use malloc - there is no much difference, except that new must be released with delete, and malloc() released with free().

UPDATE1: You can create "true" 2d array as follows:

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>;
    }
}

Just be sure to release both A and B in the end.

UPDATE2:

By popular request, this is how you can create "true" 3-dimensional array (with dimensions 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>;
        }
    }
}

This uses 2 relatively small "index" arrays A and B, and data array C. As usual, all three should be released after use.

Extending this for more dimensions is left as an exercise for the reader.




回答2:


There is nothing you can do with malloc that you can't do with new (though the converse doesn't hold). However if you've already allocated the memory in separate blocks, you will have to allocate new (contiguous) memory in order to get a connected block (with either malloc or new). The code you show allocates m non-contiguous n-sized blocks. To get an array with contiguous memory from this, you would need

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



回答3:


Ok, if the task is to maintain a single block of memory, but keep [][] way of addressing it, I'd try a few tricks with classes. The first one is an inside proxy:

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;
}

Note, that this is not time-efficient, but extremely memory efficient: uses 4 ints and 2 pointers more than original class.

There's even nicer and a lot faster solution, but you would have to resign from [][] notation in favor of (,) notation:

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;
}

Note the inline directive. It suggests the compiler to replace the method call for actual source code, which make it a little faster. This solution is even more memory efficient and a either a tiny bit less or equally time efficient as classic indexing.



来源:https://stackoverflow.com/questions/16555862/how-do-i-allocate-one-block-of-memory-with-new

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!