递归定义的数组

时间:2018-03-02 15:00:53

标签: c++ arrays recursion

我有一个关于递归定义数组中数据的排序和对齐的问题。请考虑以下代码

template<int rank, int dim, class T> struct recursive_array;

template<int dim,class Tp>
struct recursive_array <0,dim,Tp> {

    using value_type = Tp;

    recursive_array<0,dim,Tp>& operator=(Tp const& val)
    {
        value = val;
        return *this;
    }
    operator Tp &() {return value;}

    value_type value;
};


template<int rank, int dim, class Tp>
struct recursive_array {

    using value_type = recursive_array<rank-1, dim, Tp>;

    recursive_array<0,dim,Tp>& operator=(Tp const& val)
    {
        for(int i = 0; i < dim; ++i)
            values[i] = val;

        return *this;
    }

    value_type& operator[] (unsigned int const i)
    {
        return values[i];
    }

    value_type values[dim];
};

recursive_array的唯一成员是recursive_array rank-1的普通旧c阵列。在递归结束时,即rank == 0,唯一的成员value包含实际数据。这种技术在有限元库deal.II中用于描述一类通用的Tensors,以防万一你想知道我为什么不使用普通的c风格数组。

现在让我们使用recursive_array类和一个普通的旧式c风格数组定义一个2 x 2 x 2 x 2的整数数组,并比较它们在内存中的数据布局

//main.cc
#include<iostream>

int main () {

recursive_array<4,2,int> arr;
int carr[2][2][2][2];

for(int i = 0; i < 2; ++i)
    for(int j = 0; j < 2; ++j)
        for(int k = 0; k < 2; ++k)
            for(int l = 0; l < 2; ++l){

            int idx = i*8 + j*4 + k*2 + l;

            arr[i][j][k][l] = idx;
            carr[i][j][k][l] = idx;

            std::cout << ((int*)&(arr[0][0][0][0]))[idx]  << "   "
                      << ((int*)&(carr[0][0][0][0]))[idx] << std::endl;
        }

    return 0;
}

创建以下输出

0   0
1   1
2   2
3   3
4   4
5   5
6   6
7   7
8   8
9   9
10   10
11   11
12   12
13   13
14   14
15   15

使用recursive_array时,数据似乎会连续存储,因为c样式数组就是这种情况。这符合deal.II documentation,但也说

  

显示条目的顺序[...]未定义。

或者我错过了什么?

但是,独立于本文档所说的内容,我有兴趣了解上述代码的工作原理。

  1. 为什么上述代码的数据确实存储在连续的内存块中?
  2. 这有保证吗?
  3. 当数据连续存储时,元素的排序是什么?
  4. 非常感谢你!

    我使用带有-std=c++11 -O0-std=c++11 -O3标志的gcc 6.3编译了上述代码,两次都得到了相同的结果。

1 个答案:

答案 0 :(得分:1)

我是主要交易之一.II开发商;我没有为ArrayView编写特定的构造函数,但我想我仍然可以回答你的问题。

对于记录:deal.II邮件列表非常活跃,是提出这类问题的好地方。

简要版

该评论是沙漏,并且简单地说明我们可能会在未来的某个时刻修改Tensor的布局:因此,明确不鼓励在完全消除时所依赖的顺序。

更长的版本

几年前(2015年秋季),我们重写了整个Tensor课程,其定义基本上与您的示例相同;与operator[]和朋友的公共接口被重新实现以保持兼容性,但底层存储顺序改变了IIRC(我们从一些较低级别的硬编码到递归执行所有操作)。如果我们出于某种原因再次更改实现,那么内存中的顺序将会不同;因此评论。我认为该评论的作者试图提出的观点是“我们可能会改变未来的实施方式,所以不要依赖现在的事情顺序”。