C ++分配N维向量而无需复制c数组

时间:2018-08-28 15:10:37

标签: c++ arrays vector

我想将N维矩阵从磁盘(HDF5)加载到std::vector对象中。

我事先知道他们的等级,只是不知道形状。例如,矩阵之一是4级std::vector<std::vector<std::vector<std::vector<float>>>> data;

我想使用向量来存储值,因为它们是标准的,并且不如c数组丑陋(主要是因为它们知道它们的长度)。

但是,加载它们的方式是使用带有void *的加载函数,该函数对于等级1的向量很好用,在这里我可以调整它们的大小然后访问其数据指针(vector.data() )。对于较高的排名,vector.data()只会指向vector,而不是实际数据。

在最坏的情况下,我只是将所有数据加载到辅助c数组中,然后手动复制它,但这对于大型矩阵可能会使其速度大大降低。

是否有一种方法可以在向量中包含连续的多维数据,然后为其获取一个地址?

3 个答案:

答案 0 :(得分:5)

如果您担心性能,请不要使用vector ...的vector。

Here是为什么。我认为@OldPeculier的答案值得一读。

  

它既胖又慢的原因实际上是相同的。矩阵中的每个“行”都是一个单独分配的动态数组。进行堆分配在时间和空间上都是昂贵的。分配器需要一些时间来进行分配,有时需要运行O(n)算法来进行分配。分配器会用额外的字节“填充”每个行数组以进行簿记和对齐。多余的空间要花……好……多余的空间。当您去分配矩阵时,释放分配器也将花费额外的时间,并辛苦地释放每个单独的行分配。想起来让我大汗淋漓。

     

还有一个慢的原因。这些单独的分配往往存在于内存的不连续部分中。一行可能位于地址1,000,另一行可能位于地址100,000,您就会明白。这意味着当您遍历矩阵时,您像野人一样在内存中跳跃。这往往会导致高速缓存未命中,从而大大降低您的处理时间。

     

因此,如果绝对必须具有可爱的[x] [y]索引语法,请使用该解决方案。如果您想要敏捷和小巧(如果您不关心这些,为什么要使用C ++?),您需要一个不同的解决方案。

答案 1 :(得分:3)

您的计划不是明智的。向量的向量效率低下,仅对动态锯齿阵列有用,而实际上没有。

而不是您的计划,而是加载到第一个向量中。

接下来,用多维视图包装它。

template<class T, size_t Dim>
struct dimensional{
  size_t const* strides;
  T* data;
  dimensional<T, Dim-1> operator[](size_t i)const{
     return {strides+1, data+i* *strides};
  }
};
template<class T>
struct dimensional<T,0>{
  size_t const* strides; // not valid to dereference
  T* data;
  T& operator[](size_t i)const{
     return data[i];
  }
};

其中strides指向每个维度的数组步长数组(所有后续维度的大小的乘积)。

因此my_data.access()[3][5][2]得到一个特定的元素。

此解决方案的草图将所有内容公开,并且不支持for(:)迭代。更高的运输质量将具有适当的隐私权,并支持样式的循环。

我不知道已经为您编写的高质量多维数组视图的名称,但是几乎可以肯定其中的一个。

答案 2 :(得分:0)

对于二维矩阵,您可以使用像这样的丑陋c数组:

<DataGridTextColumn.CellStyle>
    <Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
        <Setter Property="ToolTip">
            <Setter.Value>
                <ToolTip>
                    <TextBlock Text="{Binding PlacementTarget.Content.Text, 
                            RelativeSource={RelativeSource AncestorType=ToolTip}}" />
                </ToolTip>
            </Setter.Value>
        </Setter>
    </Style>
</DataGridTextColumn.CellStyle>

对于三维矩阵:

float data[w * h]; //width, height
data[(y * w) + x] = 0; //access (x,y) element

以此类推。要从一个文件加载数据,

float data[w * h * d]; //width, height, depth
data[((z * h) + y) * w + x] = 0; //access (x,y,z) element

这不是很可扩展,但是您要处理一个已知尺寸。这样,您的数据是连续的,并且您只有一个地址。