Search code examples
c++arraysc++11constexprarray-view

C++ creating a 2D array using the size of a given vector, in a memory-safe manner


How do I achieve the following:

std::vector<int> vec = { 1, 2, 3 };
const int N = vec.size();
// Now create NxN 2D array.

First, I know I could do it with new but I'd have to remember to delete it later, and I'd rather not have to handle deallocation of memory if possible.

Second, I can't declare the 2D array on the stack because N is not (and can't be in this case) a constant expression. (In any case I'm using VS2013 and it doesn't support constexpr.)

Third, I can't (or maybe don't know how to) use std::array because apparently "a local variable cannot be used as a non-type argument". (I copy-pasted this from the VS2013 compile dialogue and have little understanding regarding this point).

Fourth, I'm thinking of using unique_ptr. The problem is, I know how to use unique_ptr for a 1D array, like std::unique_ptr<int> arr{ new int[N] }, but can't figure out how to do it for a 2D array.

Lastly, I know I can always write my own thin wrapper around a C-style array that's always created on the heap, or write my own 2D array class. But is there a native or standard library way of doing this in C++ (C++11)?


Solution

  • std::experimental::array_view is a view to an n-dimensional array with dynamic size bounds on a packed buffer.

    So one approach is to create a contiguous buffer (say, a std::vector<T>, or a std::unique_ptr<T[]>, and then wrap an array_view<T,2> around it.

    Access through the view object, and it will have the operations you should expect from an array. The storage is managed separately from the way of looking at the storage.

    Writing a simplified version of this array_view for the 1 and 2 dimensional case isn't tricky. But the result is your code is high performance, and very clear at point of use. The glue code (for array_view) can be a bit tricky, but once tested it should be solid: and the likelihood that a similar construct will be added to std shortly means it won't remain obscure for long.

    In my experience, once I have a solid array_view type, I use it as a drop-in replacement for where I was (inefficiently) using std::vector to pass bundles of data around in the past.

    If you want to write your own, I'd skip the bits about bounds and indexes, and just implement slicing -- [] on a 2nd dimension array_view returns a 1st dimension array_view, and [] on a 1st dimension array_view returns a T&.