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)?
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&
.