指针数组的动态 allocation/deallocation

Dynamic allocation/deallocation of array of pointers

Via Whosebug threads like this one,我发现你可以使用指针数组来管理二维数组。以前我用指针指向指针来存储二维数组,但现在我需要将我的数据存储在连续的内存中,所以指针指向指针格式不再起作用。

原始二维数组是指针数组的替代方法,但原始二维数组对我不起作用,因为我希望能够在堆中而不是堆栈中分配存储空间,因为我的容器可以非常很大,如果我使用原始二维数组,我可能会遇到堆栈溢出。

我的问题是关于如何为指针数组分配内存。我使用如下所示的 new 运算符(请参阅我的构造函数)来分配我的指针数组

#include <iostream>
using namespace std;

template<typename DataType, unsigned numRows, unsigned numCols>
class Container2D {
    public:
        Container2D() {
            m_data = new DataType[numRows][numCols];
        }
        
        ~Container2D() {
            delete [] m_data;
        }
        
        DataType* getData() { return &m_data[0][0]; }
    
    private:
        DataType (*m_data)[numCols];
    
};


int main() {
    
    Container2D<int, 3, 3> container;
    
    return 0;
}

new DataType[numRows][numCols]在堆上分配整个二维数组还是在堆上分配numRows指针,同时在堆栈上分配numCols个DataType类型的对象?

在指向指针的场景中(我将我的存储定义为 DataType** m_data),我知道我的数组的两个维度都分配在堆上,我会调用 delete m_data[i] 为每一列,然后调用 delete[] m_data 来释放我的行数据。在指针数组场景中,我不确定我上面的析构函数是否正确释放数据。

一种方法是使用一维连续数组并实现二维索引到一维索引的映射:

#include <iostream>
#include <cassert>
using namespace std;

template<typename DataType, unsigned numRows, unsigned numCols>
class Container2D {
    public:
        Container2D() { m_data = new DataType[numRows * numCols]; }
        ~Container2D() { delete [] m_data; }
        inline DataType  operator()(unsigned i, unsigned j) const {
            assert( 0 <= i && i < numRows);
            assert( 0 <= j && j < numCols);
            return m_data[i*numCols+j];
        }
        inline DataType& operator()(unsigned i, unsigned j) {
            // same as above, but this allows inplace modifications
            assert( 0 <= i && i < numRows);
            assert( 0 <= j && j < numCols);
            return m_data[i*numCols+j];
        }
    private:
        DataType* m_data;
};


int main() {
    
    Container2D<int, 3, 3> container;
    int x = container(0,0);  // retrieve the element at (0,0);
    container(1,2) = 9;      // modify the element at (1,2);
    // int y = container(3,0);  // triggers assertion errors for out-of-bound indexing
    
    return 0;
}

备注:

  • 如果 numRowsnumCols 没有针对特定的 class 实例更改,则在这种情况下不需要 newdelete。如果它们确实动态变化,最好将它们存储为成员变量而不是模板参数。如果 numRowsnumCols 太大,可以动态分配 Container2D 个对象作为一个整体。
  • 正如@GoswinvonBrederlow 评论的那样,这与 new m_data[numRows][numCols] 在内存布局方面没有区别,但这种约定使得扩展到更高维度变得更容易。

Does new DataType[numRows][numCols] allocate the entire 2D array on the heap or does it allocate numRows pointers on the heap while allocating numCols objects of type DataType on the stack?

写的时候

DataType arr[numRows][numCols];

如您所述,内存将位于一个连续块中。使用 new 时没有任何变化。它将分配一个连续的指定类型的内存块。没有隐藏的指向真实数据的指针数组。