堆上的 C++ 多维数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/340943/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:45:42  来源:igfitidea点击:

C++ Multi-dimensional Arrays on the Heap

c++arraysmemoryheapallocation

提问by eplawless

How would I go about dynamically allocating a multi-dimensional array?

我将如何动态分配多维数组?

回答by Johannes Schaub - litb

If you know the size of nested dimensions already, you can also literally allocate a multi dimensional array using new:

如果您已经知道嵌套维度的大小,您还可以使用 new 逐字分配多维数组:

typedef int dimensions[3][4];

dimensions * dim = new dimensions[10];
dim[/* from 0 to 9 */][/* from 0 to 2 */][/* from 0 to 3 */] = 42;
delete [] dim;

instead of 10, a runtime determined value can be passed. Since it's not part of the type operator new returns, that's allowed. This is nice if you know the number of columns, but want to keep the number of rows variable, for example. The typedef makes it easier to read the code.

代替10,可以传递运行时确定的值。因为它不是类型运算符 new 返回的一部分,所以这是允许的。例如,如果您知道列数,但想要保持行数可变,这很好。typedef 使代码更易于阅读。

回答by Naveen

See this: C++ FAQ by Marshall Cline

请参阅: Marshall Cline 的 C++ FAQ

See "How do I allocate multidimensional arrays using new?" and "But the previous FAQ's code is SOOOO tricky and error prone! Isn't there a simpler way?" sections.

请参阅“如何使用 new 分配多维数组?” 和“但是以前的常见问题解答代码非常棘手且容易出错!难道没有更简单的方法吗?” 部分。

回答by e.James

For the sake of completeness, here is a better way to do it in C++ when you know the array bounds ahead of time. The benefit of using the following class is that you don't have to care about calling delete[] on your data. This means that this class will be exception-safe, and all of the other great stuff about RAII.

为了完整起见,当您提前知道数组边界时,这是在 C++ 中执行此操作的更好方法。使用以下类的好处是您不必关心对数据调用 delete[]。这意味着这个类将是异常安全的,以及所有其他关于RAII 的好东西。

template<typename T, int width, int height>
class MultiArray
{
    private:
        typedef T cols[height];
        cols * data;
    public:
        T& operator() (int x, int y) { return data[x][y]; }
        MultiArray() { data = new cols[width]; }
        ~MultiArray() { delete [] data; }
};

Usage:

用法:

MultiArray<int, 10, 10> myArray;
myArray(2, 3) = 4;
cout << myArray(2, 3);

edit:and, while I'm at it, here is the setup you can use if you don'tknow the array bounds until runtime:

编辑:并且,当我在做的时候,如果您在运行时之前知道数组边界,则可以使用以下设置:

template<typename T>
class Array2D
{
    private:
        const int width;
        T * data;
    public:
        T& operator() (int x, int y) { return data[y*width + x]; }
        Array2D(const int w, const int h) : width(w) { data = new T[w*h]; }
        ~Array2D() { delete [] data; }
};

Usage:

用法:

Array2D myArray(10, 10);
myArray(3, 4) = 42;
cout << myArray(3, 4);

回答by Beno?t

How about using Boost.Multiarray ? I believe it answers your need quite well ! http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html#sec_introduction

使用 Boost.Multiarray 怎么样?我相信它可以很好地满足您的需求! http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html#sec_introduction

Here is an excerpt from the documentation page :

以下是文档页面的摘录:

 #include < boost/multi_array.hpp >

 #include < cassert >

int main () 

{

  // Create a 3D array that is 3 x 4 x 2

  typedef boost::multi_array< double, 3 > array_type;

  typedef array_type::index index;

  array_type A(boost::extents[3][4][2]);


  // Assign values to the elements

  int values = 0;

  for(index i = 0; i != 3; ++i) 

    for(index j = 0; j != 4; ++j)

      for(index k = 0; k != 2; ++k)

        A[i][j][k] = values++;

  // Verify values

  int verify = 0;

  for(index i = 0; i != 3; ++i) 

    for(index j = 0; j != 4; ++j)

      for(index k = 0; k != 2; ++k)

        assert(A[i][j][k] == verify++);

  return 0;

}

回答by Head Geek

I'm surprised no one has mentioned boost::multi_arrayyet. I needed a 2D array in a program just last week, and found it to be a lot easier, and quicker to code, than the home-brewed solutions that I've come up with before (all of which are mentioned in other comments).

我很惊讶还没有人提到boost::multi_array。上周我在一个程序中需要一个 2D 数组,发现它比我之前提出的自制解决方案更容易,更快速地编码(所有这些都在其他评论中提到) .

回答by MSalters

std::vector<std::vector<int> >should be mentioned, as it's often the simplest way. However, be aware that it is non-rectangular. Not every std::vector<int>needs to have the same length.

std::vector<std::vector<int> >应该提到,因为它通常是最简单的方法。但是,请注意它不是矩形。并非每个都std::vector<int>需要具有相同的长度。

回答by eplawless

Here's the implementation I've got; I declare a single contiguous block of ints instead of creating new blocks inside my for loop, so I'm not causing page faults all over the place. Thanks to eJames for pointing out why this code was broken originally.

这是我的实现;我声明了一个连续的ints块,而不是在我的 for 循环中创建新块,所以我不会在整个地方造成页面错误。感谢 eJames 指出为什么这段代码最初被破坏。

int width = 10, height = 10, totalSize = width*height;
int **myArray = new int*[width];
int *data = new int[totalSize];

for ( int i = 0; i < height; ++i )
{
    myArray[i] = data + (i*width);
}

// do some things here

delete[] data;
delete[] myArray;

回答by e.James

Your loop would not write the pointer values into myArrayproperly. I would suggest the following instead:

您的循环不会将指针值myArray正确写入。我建议改为:

int width = 10;
int height = 10;
int ** myArray = new int*[width];
int * data = new int[width*height];
int * index = data;
for (int i = 0; i < width; i++)
{
    myArray[i] = index;
    index += height;
}

// ...

delete[] data;
delete[] myArray;

回答by Josh Kelley

As another alternative, STLSoftincludes a fixed_array_2dclass (as well as 3D and 4D versions). Compared with the homebrewed solutions given here, it has a similar implementation but a more complete feature set (full support for iterators, etc.). Compared with boost::multi_array, it's lighter weight and easier on not-quite-compliant C++ compilers but (intentionally) lacks some of multi_array's features.

作为另一种选择,STLSoft包括一个fixed_array_2d类(以及 3D 和 4D 版本)。与这里给出的自制解决方案相比,它具有类似的实现,但功能集更完整(完全支持迭代器等)。与 boost::multi_array 相比,它在不完全兼容的 C++ 编译器上更轻,更容易,但(有意)缺少 multi_array 的一些功能。

回答by v.chaplin

This a reproduction of a post on another thread. It does exactly what you want, without needing to know the array dimensions ahead of time, and without using boost or STL.

这是另一个线程上的帖子的复制。它完全符合您的要求,无需提前知道数组维度,也无需使用 boost 或 STL。

Heres a routine which allocates the 3D array of dimension N1 x N2 x N3 in contiguous memory space while allowing you the a[i][j][k] syntax for operator access. The array is dynamic but continuous so it's a huge plus over the vector<> approach and loops of new[] calls.

这是一个例程,它在连续的内存空间中分配维度为 N1 x N2 x N3 的 3D 数组,同时允许您使用 a[i][j][k] 语法进行运算符访问。该数组是动态但连续的,因此它比 vector<> 方法和 new[] 调用循环有很大优势。

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

And later in your implementation routine...

稍后在您的实施例程中...

int *** array3d;
int N1=4, N2=3, N3=2;

int elementNumber = 0;

array3d = Create3D<int>(N1,N2,N3);

//equivalently, a 'flat' array could be obtained with
//int * array = array3d[0][0];

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] << " ";

            //or if you're using the flat array:
            //array[i*N2*N3 + j*N3 + k] = elementNumber++;

        }
        cout << "}";
    }
    cout << "}";
    cout << endl ;
}
cout << "}" << endl;

Delete3D(array3d);

Gives the output:

给出输出:

{
{{   0    1 }{   2    3 }{   4    5 }}
{{   6    7 }{   8    9 }{  10   11 }}
{{  12   13 }{  14   15 }{  16   17 }}
{{  18   19 }{  20   21 }{  22   23 }}
}