【问题标题】:Create a multidimensional array dynamically in C++在 C++ 中动态创建多维数组
【发布时间】:2018-05-19 17:37:36
【问题描述】:

什么是在 C++ 中动态创建多维数组的好方法(了解惯用/良好实践)。

例如,假设我有树整数 w、h 和 d,我想创建一个数组 MyEnum my_array[w][h][d]。 (当然 w、h 和 d 在编译时是未知的)。

最好是使用嵌套的 std::vector 还是使用 new 什么的?

额外问题:是否也可以动态设置维度?

【问题讨论】:

    标签: c++ arrays multidimensional-array dynamic-allocation


    【解决方案1】:

    一般来说,嵌套std::vector 并不是一个好主意。分配内存通常是一个更好的计划,它将整个多维数组保存为一个连续的块,然后将其索引到它就好像它是多维的。此内存块可以通过new 分配,但除非您需要精确控制它的分配方式(自定义分配器),否则我建议坚持使用单个std::vector。

    创建一个类来管理这样一个可以动态设置维数的资源并不难。组织此类的一个好方法是跟踪分配的内存、每个维度的大小以及每个维度的步幅模式。步幅描述了必须增加多少元素才能沿给定维度到达下一个元素。

    这允许高效的索引(只是指针算术),以及非常高效的整形:只要元素的数量不改变,这只需要改变形状和步幅数组。


    示例:

    这是一个非常基本的类,它将存储doubles 的动态多维数组。它以行优先顺序存储数据,这意味着最后一个索引变化最快。所以对于二维数组,第一行是连续存储的,然后是第二行,以此类推。

    如果需要,您可以重新调整数组的形状,更改维数。还显示了基本元素访问operator[]。该类没有其他花哨的东西,但您可以对其进行扩展以提供您想要的任何功能,例如迭代器、对数据的数学运算、I/O 运算符等。

    /*! \file dynamic_array.h
     * Basic dynamic multi-dimensional array of doubles.
     */
    
    #ifndef DYNAMIC_ARRAY_H
    #define DYNAMIC_ARRAY_H
    
    #include <vector>
    #include <numeric>
    #include <functional>
    
    class
    dynamic_array
    {
        public:
            dynamic_array(const std::vector<int>& shape)
                : m_nelem(std::accumulate(shape.begin(), shape.end(),
                            1, std::multiplies<int>()))
                , m_ndim(shape.size())
                , m_shape(shape)
            {
                compute_strides();
                m_data.resize(m_nelem, 0.0);
            }
    
            ~dynamic_array()
            {
            }
    
            const double& operator[](int i) const
            {
                return m_data.at(i);
            }
    
            double& operator[](int i)
            {
                return m_data.at(i);
            }
    
            const double& operator[](const std::vector<int>& indices) const
            {
                auto flat_index = std::inner_product(
                        indices.begin(), indices.end(),
                        m_strides.begin(), 0);
                return m_data.at(flat_index);
            }
    
            double& operator[](const std::vector<int>& indices)
            {
                auto flat_index = std::inner_product(
                        indices.begin(), indices.end(),
                        m_strides.begin(), 0);
                return m_data.at(flat_index);
            }
    
            void reshape(const std::vector<int>& new_shape)
            {
                auto new_nelem = std::accumulate(
                        new_shape.begin(), new_shape.end(),
                        1, std::multiplies<int>());
                if (new_nelem != m_nelem) {
                    throw std::invalid_argument("dynamic_array::reshape(): "
                            "number of elements must not change.");
                }
                m_nelem = new_nelem;
                m_ndim = new_shape.size();
                m_shape = new_shape;
                compute_strides();
            }
    
            const std::vector<int>& shape() const
            {
                return m_shape;
            }
    
            const std::vector<int>& strides() const
            {
                return m_strides;
            }
    
            int ndim() const
            {
                return m_ndim;
            }
    
            int nelem() const
            {
                return m_nelem;
            }
    
        private:
            int m_ndim;
            int m_nelem;
            std::vector<int> m_shape;
            std::vector<int> m_strides;
            std::vector<double> m_data;
    
            void compute_strides()
            {
                m_strides.resize(m_ndim);
                m_strides.at(m_ndim - 1) = 1;
                std::partial_sum(m_shape.rbegin(),
                        m_shape.rend() - 1,
                        m_strides.rbegin() + 1,
                        std::multiplies<int>());
            }
    };
    
    #endif // include guard
    

    这是该功能的基本演示。

    /*! \file test.cc
     * Basic test of the dynamic_array class.
     */
    #include "dynamic_array.h"
    #include <iostream>
    
    int main(int /* argc */, const char * /* argv */[])
    {
        dynamic_array arr({2, 3});
        std::cout << "Shape: { ";
        for (auto& each : arr.shape())
            std::cout << each << " ";
        std::cout << "}" << std::endl;
    
        std::cout << "Strides: { ";
        for (auto& each : arr.strides())
            std::cout << each << " ";
        std::cout << "}" << std::endl;
    
        // Reshape array, changing number of dimensions, but
        // keeping number of elements constant.
        arr.reshape({6});
        std::cout << "Shape: { ";
        for (auto& each : arr.shape())
            std::cout << each << " ";
        std::cout << "}" << std::endl;
    
        // Verify that the stride pattern has now also changed.
        std::cout << "Strides: { ";
        for (auto& each : arr.strides())
            std::cout << each << " ";
        std::cout << "}" << std::endl;
    
        return 0;
    }
    

    你可以用g++ -std=c++14 -o test test.cc编译测试程序,假设定义类的文件和test.cc在同一目录下。

    【讨论】:

    • 谢谢你,这就是我正在寻找的答案!
    猜你喜欢
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 2014-08-14
    • 2017-12-10
    相关资源
    最近更新 更多