我如何声明一个2d数组使用新?

比如,对于一个“普通”数组,我将:

int* ary = new int[Size]

but

int** ary = new int[sizeY][sizeX]

A)不工作/编译b)没有完成什么:

int ary[sizeY][sizeX] 

所做的事。


当前回答

这个问题一直困扰着我——这是一个很常见的问题,应该已经有了一个好的解决方案,比向量的向量或滚动你自己的数组索引更好的解决方案。

当c++中应该存在一些东西,但却不存在时,第一个地方是boost.org。在那里我找到了Boost多维数组库,multi_array。它甚至包括一个multi_array_ref类,可用于包装您自己的一维数组缓冲区。

其他回答

这个问题一直困扰着我——这是一个很常见的问题,应该已经有了一个好的解决方案,比向量的向量或滚动你自己的数组索引更好的解决方案。

当c++中应该存在一些东西,但却不存在时,第一个地方是boost.org。在那里我找到了Boost多维数组库,multi_array。它甚至包括一个multi_array_ref类,可用于包装您自己的一维数组缓冲区。

这里,我有两个选择。第一个展示了数组的数组或指针的指针的概念。我更喜欢第二个,因为地址是连续的,正如您在图像中看到的那样。

#include <iostream>

using namespace std;


int main(){

    int **arr_01,**arr_02,i,j,rows=4,cols=5;

    //Implementation 1
    arr_01=new int*[rows];

    for(int i=0;i<rows;i++)
        arr_01[i]=new int[cols];

    for(i=0;i<rows;i++){
        for(j=0;j<cols;j++)
            cout << arr_01[i]+j << " " ;
        cout << endl;
    }


    for(int i=0;i<rows;i++)
        delete[] arr_01[i];
    delete[] arr_01;


    cout << endl;
    //Implementation 2
    arr_02=new int*[rows];
    arr_02[0]=new int[rows*cols];
    for(int i=1;i<rows;i++)
        arr_02[i]=arr_02[0]+cols*i;

    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++)
            cout << arr_02[i]+j << " " ;
        cout << endl;
    }

    delete[] arr_02[0];
    delete[] arr_02;


    return 0;
}

在c++ 11及以上版本中,我推荐两种通用技术,一种用于编译时维度,另一种用于运行时维度。这两个答案都假设您需要统一的二维数组(而不是锯齿状数组)。

编译时维度

使用std::array的std::array,然后使用new把它放到堆上:

// the alias helps cut down on the noise:
using grid = std::array<std::array<int, sizeX>, sizeY>;
grid * ary = new grid;

同样,这仅适用于在编译时已知维度大小的情况。

运行时维度

实现只有在运行时才知道大小的二维数组的最佳方法是将其包装到一个类中。该类将分配一个1d数组,然后重载操作符[]来为第一个维度提供索引。 这是因为在c++中,2D数组是行为主的:

(摘自http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/)

连续的内存序列有利于提高性能,而且易于清理。下面是一个示例类,省略了很多有用的方法,但显示了基本思想:

#include <memory>

class Grid {
  size_t _rows;
  size_t _columns;
  std::unique_ptr<int[]> data;

public:
  Grid(size_t rows, size_t columns)
      : _rows{rows},
        _columns{columns},
        data{std::make_unique<int[]>(rows * columns)} {}

  size_t rows() const { return _rows; }

  size_t columns() const { return _columns; }

  int *operator[](size_t row) { return row * _columns + data.get(); }

  int &operator()(size_t row, size_t column) {
    return data[row * _columns + column];
  }
}

因此,我们用std::make_unique<int[]>(行*列)项创建一个数组。我们重载操作符[],它将为我们索引行。它返回一个int *,指向该行的开头,然后可以像对列一样对该行进行解引用。注意,make_unique在c++ 14中首次发布,但如果需要,可以在c++ 11中填充它。

对于这些类型的结构,重载operator()也是很常见的:

  int &operator()(size_t row, size_t column) {
    return data[row * _columns + column];
  }

从技术上讲,我在这里没有使用new,但是从std::unique_ptr<int[]>移动到int *并使用new/delete是很简单的。

如果只在本地或类中使用数组,则可以使用lambda表达式创建类数组对象。

int main(int argc, char **argv) {
  srand(time(0));
  int w = rand() % 20 + 10;
  int h = rand() % 20 + 10;
  {
    // Here. Only one line and no memory leak.
    auto arr = [=, p = std::make_unique<int[]>(w * h)](int i, int j) -> int & { return *&p[i * w + j]; };
    arr(1, 0) = 6;
    std::cout << arr(1, 0) << '\n';
  }
}

该对象与int[][]不兼容,要将其作为参数传递,需要模板。但是当你访问一个元素时,它可以让你摆脱正确获取[i * w + j]的麻烦。

你也可以使用一个裸std::unique_ptr<int[]>和一个在lambda中实现的getter。但你可能会犯错误,引用不明确。

我使用这个不优雅,但快速,简单和工作系统。我不明白为什么不能工作,因为系统允许创建一个大尺寸数组和访问部分的唯一方法是不切割它的部分:

#define DIM 3
#define WORMS 50000 //gusanos

void halla_centros_V000(double CENW[][DIM])
{
    CENW[i][j]=...
    ...
}


int main()
{
    double *CENW_MEM=new double[WORMS*DIM];
    double (*CENW)[DIM];
    CENW=(double (*)[3]) &CENW_MEM[0];
    halla_centros_V000(CENW);
    delete[] CENW_MEM;
}