Correct channel for dynamic memory allocation for large tables in C ++?


I was wondering what is the easiest and of course most accurate way for dynamic memory allocation for a 4-D array in C++. What I already know is the following:

double**** A;
A = new double***[s1];
for (i = 0; i < s1; i++) {
    A[i] = new double**[s2];
    for (j = 0; j < s2; j++) {
        A[i][j] = new double*[s3];
        for (k = 0; k < s3; k++) {
            A[i][j][k] = new double[s4];

to declare A as a 4-D array of dimensions s1xs2xs3xs4.

However, the above is not safe. In the sense that if one of the news fail to allocate the memory the loops continue without noticing this.

To make the above a bit safer, we can enclose it in a try/catch block so that the code does not continue after a bad_alloc has been thrown by new and the code will not try to access some non-existent memory elements and the program can halt at this point.

This is OK with the exception that the memory that has already been allocated will not be released before the program finishes. Theoretically with the values of i, j, and k we must be able to precisely say which memory elements are already allocated and release them. But I cannot think of a straightforward way of doing it.

For a 2-D case I would do something like this:

double** A;
try {
    A = new double*[s1];
} catch(bad_alloc& ba) {
    delete[] A;
    throw ba; // or end the program
try {
    for (i = 0; i < s1; i++)
        A[i] = new double[s2];
} catch(bad_alloc& ba) {
    while(--i) {
        delete[] A[i];
    delete[] A;
    throw ba; // or end the prog.

The above could be generalized to higher dimensional arrays but I guess it would be very ugly! So I wonder if there is a better way for doing that?

I guess I should also mention that in my case A[i][j][k] is a vector with very few non-zero elements. Hence, I only take s3 to be as big as the number of non-zero elements (and then take care of mapping indices and ... later). s3, however, depends on j. That's why using the traditional memory allocation is easier than higher-level APIs like vector

std::vector<std::vector<std::vector<std::vector<double>>>> A;

That will get you a 4D dynamic array without the worry of managing the exception safety (for memory allocations at least).

If you want a static array:

std::array<std::array<std::array<std::array<double, N>, N>, N>, N> B;

Side Note: If you are nesting that far, you can probably gain a lot through refactoring.

That's why using the traditional memory allocation is easier than higher-level APIs like vector

That is a flawed assertion. You have a non-sparse 4D array - you gain next to nothing by using "traditional memory allocation" over using std::vector or std::array or even a Boost Multiarray. All of the same steps you have to take for proper memory management and exception safety are already done (and well tested) in those classes, whereas a custom implementation is not.