Reputation: 2469
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 s1
xs2
xs3
xs4
.
However, the above is not safe. In the sense that if one of the new
s 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
Upvotes: 1
Views: 1493
Reputation: 15872
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.
Upvotes: 3
Reputation: 170143
If you really must have a block of memory which is an N-d array, you could try the following:
int* raw_mem = new int [S1 * S2 * S3];
int (*arr)[S2][S3] = (int (*)[S2][S3]) raw_mem;
This merely has the block of memory be addressed like a true 3-d array.
Now, this is the worst way to do it. You should use some higher level API that is suggested in other answers. But it is possible to treat a block of memory as a C multi-array.
Upvotes: 2