(This is not a duplicate of this or this that refer to fixed sizes, the issue is not to understand how pointers are stored, but if the compiler can automate the manual funct
Your code invokes undefined behavior because x.data() does not point to an array of pointers but to an array of 1000 objects of type char. You should be thankful that it crashes… ;-)
One way to access a contiguous buffer of some type as if it was a multidimensional array is to have another object that represents a multidimensional view into this buffer. This view object can then, e.g., provide member functions to access the data using a multidimensional index. To enable the a[i][j][k] kind of syntax (which you seem to be aiming for), provide an overloaded [] operator which returns a proxy object that itself offers an operator [] and so on until you get down to a single dimension.
For example, for the case that dimensions are fixed at compile time, we can define
template
struct row_major_layout;
template
struct row_major_layout
{
template
static auto view(T* data) { return data; }
};
template
struct row_major_layout
{
static constexpr int stride = (Extents * ... * 1);
template
class span
{
T* data;
public:
span(T* data) : data(data) {}
auto operator[](std::size_t i) const
{
return row_major_layout::view(data + i * stride);
}
};
template
static auto view(T* data) { return span(data); }
};
and then simply create and access such a row_major_layout view
void test()
{
constexpr int M = 7, N = 2, K = 5;
std::vector bla(row_major_layout::size);
auto a3d = row_major_layout::view(data(bla));
a3d[2][1][3] = 42;
}
live example here
Or in case the array bounds are dynamic:
template
class row_major_layout;
template <>
class row_major_layout<1>
{
public:
row_major_layout(std::size_t extent) {}
static constexpr std::size_t size(std::size_t extent)
{
return extent;
}
template
friend auto view(T* data, const row_major_layout&)
{
return data;
}
};
template
class row_major_layout : row_major_layout
{
std::size_t stride;
public:
template
row_major_layout(std::size_t extent, Dim&&... extents)
: row_major_layout(std::forward(extents)...), stride((extents * ... * 1))
{
}
template
static constexpr std::size_t size(std::size_t extent, Dim&&... extents)
{
return extent * row_major_layout::size(std::forward(extents)...);
}
template
class span
{
T* data;
std::size_t stride;
const row_major_layout& layout;
public:
span(T* data, std::size_t stride, const row_major_layout& layout)
: data(data), stride(stride), layout(layout)
{
}
auto operator[](std::size_t i) const
{
return view(data + i * stride, layout);
}
};
template
friend auto view(T* data, const row_major_layout& layout)
{
return span(data, layout.stride, layout);
}
};
and
void test(int M, int N, int K)
{
std::vector bla(row_major_layout<3>::size(M, N, K));
auto a3d = view(data(bla), row_major_layout<3>(M, N, K));
a3d[2][1][3] = 42;
}
live example here