C++ Multidimensional array in existing memory

前端 未结 4 2099
既然无缘
既然无缘 2020-12-19 20:58

(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

4条回答
  •  再見小時候
    2020-12-19 21:19

    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

提交回复
热议问题