There are twothree general techniques that I would recommend for this in C++11 and above, one for compile time dimensions and one for run time. Both:
- One for dimensions known at compile-time.
- One for dimensions known at run-time and using < C++23
- One for dimensions known at run-time and using >= C++23
All answers assume you want uniform, two-dimensional arrays (not jagged ones).
// the alias helps cut down on the noise:
using grid = std::array<std::array<int, sizeX>, sizeY>;
grid * ary = new grid;
// the alias helps cut down on the noise:
using grid = std::array<std::array<int, sizeX>, sizeY>;
grid * ary = new grid;
Run time-time dimensions (< C++23)
The best way to accomplish a 2 dimensional array with sizes only known at runtimerun-time is to wrap it into a class. The class will allocate a 1d array and then overload operator []
to provide indexing for the first dimension.
This works because in C++ a 2D array is row-major:
Run-time dimensions (C++23)
For C++23, there is std::mdspan
. This view generalizes a contiguous region of memory into a multi-dimension view. For instance, a 1x12 region of memory could be a 4x3 or 2x3x2, and so on, as long as the view actually makes sense on top of the underlying memory region. Here's an example:
#include <mdspan>
#include <print>
#include <vector>
int main() {
std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// View data as contiguous memory representing 2 rows of 6
// ints each
auto ms2 = std::mdspan(v.data(), 2, 6);
// View the same data as a 3D array 2 x 3 x 2
auto ms3 = std::mdspan(v.data(), 2, 3, 2);
// write data using 2D view
for (size_t i = 0; i != ms2.extent(0); i++)
for (size_t j = 0; j != ms2.extent(1); j++)
ms2[i, j] = i * 1000 + j;
// read back using 3D view
for (size_t i = 0; i != ms3.extent(0); i++) {
std::println("slice @ i = {}", i);
for (size_t j = 0; j != ms3.extent(1); j++) {
for (size_t k = 0; k != ms3.extent(2); k++)
std::print("{} ", ms3[i, j, k]);
std::println("");
}
}
}