Home > Software engineering >  Dynamic allocation/deallocation of array of pointers
Dynamic allocation/deallocation of array of pointers

Time:05-29

Via stackoverflow threads like this one, I discovered that you could use an array of pointers to manage a 2D array. In the past I used to use pointer to pointer to store 2D arrays, but now I have a requirement to store my data in contiguous memory, so pointer to pointer format doesn't work anymore.

A raw 2D array is an alternative to array of pointers, but raw 2D array doesn't work for me because I want to be able to allocate storage in the heap and not on the stack because my container can be very large and I might encounter stack overflow if I use vanilla 2D array.

My question is about how memory is allocated for array of pointers. I use new operator like below (see my constructor) to allocate my array of pointers

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

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?

In a pointer to pointer scenario (where I'd define my storage as DataType** m_data), I know for a fact that both dimensions of my array are allocated on the heap and I would call delete m_data[i] for each column and then call delete[] m_data to free my row data. In the array of pointers scenario, I'm not sure if my destructor above is freeing up data correctly.

CodePudding user response:

Based on your requirement on contiguous storage, a better practice is to use a 1D contiguous array and implement the 2D index to 1D index mapping instead:

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

template<typename DataType, unsigned numRows, unsigned numCols>
class Container2D {
    public:
        Container2D() { m_data = new DataType[numRows * umCols]; }
        ~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;
}

A smaller note: if numRows and numCols do not change for a specific class instance, new and delete are not necessary in this case. If they do dynamically change, it is better to store them as member variables instead of template parameters.

CodePudding user response:

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?

When you write

DataType arr[numRows][numCols];

the memory will be in one contiguos block as you mentioned. Nothing changes there when you use new. It will allocate one contiguos block of memory of the specified type. There is no hidden array of pointers into the real data.

  • Related