首页 > 解决方案 > 使用向量在 C++ 中声明 3D 数组结构

问题描述

嗨,我是一名使用 C++ 学习科学计算的研究生。我们的一些研究集中在算法的速度上,因此构造足够快的数组结构很重要。

我见过两种构造 3D 数组的方法。第一个是使用矢量库。

vector<vector<vector<double>>> a (isize,vector<double>(jsize,vector<double>(ksize,0)))

这给出了大小为 isize x jsize x ksize 的 3D 数组结构。

另一种是构造一个包含大小为 isize* jsize * ksize 的一维数组的结构,使用

new double[isize*jsize*ksize]. 要轻松访问 (i,j,k) 的特定位置,需要运算符重载(对吗?)。

根据我的经验,第一个要快得多,因为它可以轻松访问位置 (i,j,k),而后一个必须计算位置并返回值。但是我看到有些人更喜欢后一种而不是第一种。为什么他们更喜欢后一种设置?使用第一个有什么缺点吗?

提前致谢。

标签: c++arraysvector

解决方案


它们之间的主要区别在于布局:

vector<vector<vector<T>>>

这将为您提供一维数组vector<vector<T>>
每个项目将是一维数组vector<T>
并且这些一维数组中的每一项都是 T 的一维数组。

关键是,vector它本身不存储其内容。它管理一块内存,并将内容存储在那里。这会带来许多不好的后果:

  1. 对于维度 X·Y·Z 的矩阵,您最终将分配1 + X + X·Y内存块。这非常慢,并且会破坏堆。想象一下:一个大小为 20 的立方体矩阵会触发 421 次调用new
  2. 要访问一个单元格,您有 3 个间接级别:
    • 您必须访问该vector<vector<vector<T>>>对象以获取指向顶级内存块的指针。
    • 然后,您必须访问该vector<vector<T>>对象以获取指向二级内存块的指针。
    • 然后,您必须访问该vector<T>对象以获取指向叶子内存块的指针。
    • 只有这样您才能访问T数据。
  3. 这些内存块将分布在堆周围,导致大量缓存未命中并减慢整体计算速度。
  4. 如果您在某些时候弄错了,可能会导致矩阵中的某些行具有不同的长度。毕竟,它们是独立的一维数组。

new T[X * Y * Z]另一方面,拥有一个连续的内存块(如)给出:

  1. 您分配 1 个内存块。没有堆垃圾,O(1)。
  2. 您只需要访问指向内存块的指针,然后就可以直接获取所需的元素。
  3. 所有矩阵在内存中都是连续的,这是缓存友好的。

在那些日子里,单个缓存未命中意味着数十或数百个计算周期丢失,不要低估缓存友好性方面。

顺便说一句,您可能没有提到一种更好的方法:使用众多矩阵库之一,它会自动为您处理这个问题并提供很好的支持工具(如 SSE 加速矩阵运算)。一个这样的库是Eigen,但还有很多其他的。

→ 你想做科学计算?让一个库处理样板和基础知识,这样您就可以专注于科学计算部分。


推荐阅读