【问题标题】:5-dimensional vector declaration5维向量声明
【发布时间】:2014-12-26 20:51:55
【问题描述】:

我正在寻找一种在 C++ 中声明 5 维数组的优雅方式。

每个嵌套向量都有已知的大小,所以我开始做:

std::vector<std::vector<std::vector<std::vector<double>>>> myDblVec;

然后假设我知道所有尺寸:

myDblVec.resize(dim1);
for (int d1 = 0; d1 != dim1; d1++) {
    myDblVec[d1].resize[dim2];
    for (int d2 = 0; d2 != dim2; d2++) {
        myDblVec[d1][d2].resize(dim3)
        for (int d3 = 0; d3 != dim3; d3++) {
            myDblVec[d1][d2][d3].resize(dim4);
        }
    }
}

我正在寻找一个 1-liner 或不那么“重”的东西来声明这个数组。

【问题讨论】:

  • 我为 n 维数组创建了一个自定义类,该类以每个子数组的已知大小进行初始化。 stackoverflow.com/questions/26665096/…
  • a) 数组有固定大小吗? b) 你只有少量数据吗?我问这个是因为一个向量中的一个向量在一个......只是感觉......好吧,错了。
  • a) 不,但测试是的 b) 数据代表图像,因此可能非常庞大。数组大小会随着图像分辨率的改变而改变。

标签: c++ vector multidimensional-array


【解决方案1】:

如果你得到维度运行时,比如

myDblVec = std::vector<std::vector<std::vector<std::vector<double>>>>(dim1,
    std::vector<std::vector<std::vector<double>>>(dim2,
        std::vector<std::vector<double>>(dim3, 
            std::vector<double>>(dim4, 0.0))));

【讨论】:

  • 不错。使用这个 VS 数组的任何优点和缺点(主要是性能方面)。我知道维度运行时,但我的数组/向量是类定义的一部分,我只知道我的类被初始化后的大小。所以我必须通过某种init函数重新声明它。
  • @Julien 数组(包括std::array)是在编译期间分配的,因此在编译时必须知道维度作为编译时常量。它们也不是直接从堆中分配的,所以如果维度足够大,很容易导致堆栈溢出。
【解决方案2】:

你可以使用std::array,假设大小在编译时是已知的:

std::array<std::array<std::array<std::array<double, dim4>, dim3>, dim2>, dim1> myDblArray;

【讨论】:

    【解决方案3】:

    如果您不太喜欢 C++11 之前的版本,您可以编写一个简单的可变参数模板:

    template <typename T, size_t... N> struct NestedArray;                                                                                                                                                
    
    template <typename T, size_t N> struct NestedArray<T, N> {                                                                                                                                            
      using type = array<T, N>;                                                                                                                                                                           
    };
    
    template <typename T, size_t N, size_t... Rest>
    struct NestedArray<T, N, Rest...> {
      using type = array<typename NestedArray<T, Rest...>::type, N>;
    };
    

    现在,您可以将数组定义为NestedArray&lt;double, dim1, dim2, dim3, dim4&gt;::type

    【讨论】:

    • 我不是在寻找增加的复杂性,而是在寻找。我是 C++ 新手,所以尝试使用内置功能(这是有道理的 :)
    【解决方案4】:

    std::vector&lt;T&gt; 将大小作为第一个构造函数参数。您可以利用这一点并按照以下方式使用一些东西

    make_vector_t<double, 5> myDblVec(init_vector<double, 5>(dim1, dim2, dim3, dim4, dim5));
    

    这将需要一些基础设施来创建类型和初始化元素。当然,这个基础设施是合理的(虽然我还没有编译它——目前我只是在使用移动设备,也就是说,几乎可以肯定有一个错字,但整体方法应该是可行的):

    template <typename T, int Dim> struct make_vector;
    template <typename T, int Dim>
    using make_vector_t = typename make_vector<T, Dim>::type;
    template <typename T>
    struct make_vector<T, 0> { using type = T; }
    template <typename T, int Dim>
    struct make_vector { using type = std::vector<make_vector_t<T, Dim-1>>; }
    
    template <typename T, int Dim, typename Arg, typename... Args>
    auto init_vector(Arg size, Args... sizes) -> make_vector_t<T, Dim-1> {
        return make_vector_t<T, Dim>(size, init_vector<T, Dim-1>(sizes...);
    }
    

    【讨论】:

      【解决方案5】:

      如果您非常需要多维数组,请考虑将必须处理它们的东西移到使用 C 而不是 C++ 的单独源文件中。您可以很容易地在语言之间进行交互,并且在 C 中分配动态大小的 5D 数组就像

      double (*fiveDArray)[dim2][dim3][dim4][dim5] = malloc(dim1 * sizeof(*fiveDArray));
      

      用法与嵌套的std::vector&lt;&gt;s 几乎相同,您只需要记住在完成数组后调用free()。如果您需要一个零初始化数组,请将malloc() 替换为calloc()。作为一个额外的好处,C 多维数组的连续性在 CPU 缓存上比使用std::vector&lt;&gt; 更好,而且索引更快,因为只有一个指针可以追踪。

      C++ 不允许这样做,因为这种语言将数组维度限制为编译时常量。另一方面,C 已经取消了 C99 标准中的这一限制,甚至允许 typedef 中的动态数组大小:

      void foo(size_t dim1, size_t dim2, size_t dim3, size_t dim4, size_t dim5) {
          typedef double FourDSlice[dim2][dim3][dim4][dim5];
          FourDSlice *fiveDArray = malloc(dim1 * sizeof(*fiveDArray));
      
          ...
      }
      

      是完全合法的 C99,在 C++ 中是不可能的。

      【讨论】:

        【解决方案6】:

        嗯...vector&lt;vector&gt; 这真的是一件好事吗?你在考虑一个矩阵,它的行可以有独立的长度吗?如果答案是“否”,那么考虑一下您所需要的只是一个普通向量,其大小是 5 维的乘积,其元素位于

        size_t at(size_t a, size_t b, size_t c, size_t d, size_t e, size_t A, size_t B, size_t C, size_t D, size_t E)
        { return e+d*E+c*D*E+b*C*D*E+a*B*C*D*E; }
        

        (注意:大写字母是大小)。

        您可以使用 varadics 轻松地将其推广到任意数量的维度:

        template<class... I>
        size_t at(size_t r, size_t R, size_t c, size_t C, I... i)
        { return size_at(r*C+c,i...); }
        
        size_t at(size_t c, size_t C)
        { return c; }
        

        您还可以将所有这些嵌入到循环类中

        template<class T, size_t Rank>
        class grid
        {
            grid<T,Rank-1> m; size_t C;
        public:
            template<class... I>
            grid(size_t r, size_t c, I... i) :m(r*c,i...) :C(c) {}
        
            template<class... I>
            T& operator()(size_t r, size_t c, I... i)
            { return m(r*C+c,i...); }
        
            template<class... I>
            const T& operator()(size_t r, size_t c, I... i) const 
            { return m(r*C+c,i...); }
        };
        
        template<class T>
        class grid<T,1>
        {
            std::vector<T> m;
        public:
            explicit grid(size_t n) :m(n) {}
        
            T& operator()(size_t i) { return m[i]; }
            const T& operator()(size_t i) const { return m[i]; }
        };
        

        你可以声明一个grid&lt;5&gt; a(3,2,4,5,3); 并以a(x,y,z,w,t); 访问其元素,无论 x 在 0..2、y 在 0..1、z 在 0..3 w 在 0..4 和 t 在 0..2;

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-26
          相关资源
          最近更新 更多