用矢量声明C++中的三维数组结构 我是一名研究C++科学计算的研究生。我们的一些研究侧重于算法的速度,因此构建足够快的阵列结构非常重要

用矢量声明C++中的三维数组结构 我是一名研究C++科学计算的研究生。我们的一些研究侧重于算法的速度,因此构建足够快的阵列结构非常重要,c++,arrays,vector,C++,Arrays,Vector,我见过两种构建3D阵列的方法。 第一种是使用向量库 vector<vector<vector<double>>> a (isize,vector<double>(jsize,vector<double>(ksize,0))) 这给出了大小为isize x jsize x ksize的3D阵列结构 另一个是使用 新的双精度[isize*jsize*ksize]。要轻松访问i、j、k的特定位置,必须使用运算符重载,对吗 根据我的经验,第一

我见过两种构建3D阵列的方法。 第一种是使用向量库

vector<vector<vector<double>>> a (isize,vector<double>(jsize,vector<double>(ksize,0)))
这给出了大小为isize x jsize x ksize的3D阵列结构

另一个是使用

新的双精度[isize*jsize*ksize]。要轻松访问i、j、k的特定位置,必须使用运算符重载,对吗

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


感谢您的支持。

在我看来,std::vector比普通平面阵列有太多的优势

简言之,以下是一些:

使用std::vector创建内存泄漏要困难得多。这一点本身就是最大的优势之一。这与性能无关,但应始终予以考虑。 向量是STL的一部分。C++的这一部分是最常用的部分之一。成千上万的人使用STL,因此他们每天都要接受测试。在过去的几年里,它们得到了彻底的优化,不再缺乏任何性能。如果我看错了,请纠正我 使用std::vector处理像1、2、3这样简单。没有指针处理没有什么。。。只需通过方法或使用[]-运算符和更多其他方法访问它。
首先,在你的vec^3中直接访问i,j,k的想法有点缺陷。您拥有的是一个指针结构,在此结构中,您需要在整个过程中取消引用三个指针。注意,我不知道这比计算一维数组中的位置快还是慢。您需要对此进行测试,这可能取决于数据的大小,尤其是数据是否适合一个数据块

其次,向量^3需要指针和向量大小,这需要更多内存。在许多情况下,这与图像的立方增长无关,但内存差异只是二次增长,但如果你的算法真的要填满任何可用内存,这可能很重要

第三,原始数组将所有内容存储在连续内存中,这有利于流式处理,并且由于缓存访问速度快,因此对某些算法也有好处。例如,将一个三维图像添加到另一个三维图像时

请注意,所有这些都是关于您可能不需要的超级优化。skratchi.at在他的回答中指出的向量的优点是非常强大的,我补充了向量通常增加可读性的优点。如果你没有很好的理由不使用向量,那么就使用它们


如果您决定使用原始阵列,在任何情况下,请确保包装良好,并保持类的小型化和简单化,以解决与泄漏等相关的问题。

这些问题的主要区别在于布局:

vector<vector<vector<T>>>
这将得到一维向量数组。 每个项目将是一个一维向量数组。 这些一维数组中的每一项都是T的一维数组

关键是,向量本身不存储其内容。它管理一块内存,并将内容存储在那里。这有许多不良后果:

对于维度为X·Y·Z的矩阵,最终将分配1+X+X·Y内存块。这是可怕的缓慢,并将垃圾堆。想象一下:一个大小为20的立方体矩阵将触发421个对new的调用! 要访问单元格,您有3个间接级别: 必须访问vector对象才能获取指向顶级内存块的指针。 然后,必须访问vector对象以获取指向第二级内存块的指针。 然后,必须访问vector对象以获取指向叶内存块的指针。 只有这样,您才能访问T数据。 这些内存块将分布在堆中,导致大量缓存未命中并降低总体计算速度。 如果你在某一点上弄错了,那么你的矩阵中的一些线可能会有不同的长度。毕竟,它们是独立的一维阵列。 另一方面,具有类似于new T[X*Y*Z]的连续存储器块给出:

分配1个内存块。没有堆垃圾,O1。 您只需要访问指向内存块的指针,就可以直接找到所需的元素。 所有矩阵在内存中都是连续的,这是缓存友好的。 在那些日子里,一次缓存丢失意味着几十个或数百个计算周期的丢失,不要低估缓存友好性。

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

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

欢迎使用so

如果你所有的东西都是两种选择,那么第一种可能会更好

<>你应该避免使用C++的纯数组,因为你需要管理你自己的内存分配/重新分配,比如新的/Delphi和其他样板代码,比如跟踪大小/检查边界。很明显,C数组不太安全,并且没有数组和向量的优势

然而,第一种选择有一些重要的缺点。我想强调的是:

std::vector<std::vector<std::vector<T>>>
不是三维矩阵。在矩阵中,所有行的大小必须相同。另一方面,在向量的向量中,不能保证所有嵌套向量具有相同的长度。原因是向量是@spectras答案中指出的线性一维结构。因此,为了避免所有类型的不良或意外行为,您必须在代码中包含保护以获得保证的矩形不变量

幸运的是,第一种选择并不是你手中唯一的选择

例如,可以用std::array替换c样式数组:

const int n = i_size * j_size * k_size;

std::array<int, n> myFlattenMatrix;
或者使用std::vector,以防矩阵尺寸发生变化

通过元素的3个坐标访问元素

关于你的问题

要方便地访问i、j、k的特定位置,请选择操作员 超载是必要的,对吗

不完全是。由于std::vector和array都没有3参数运算符,所以不能重载它。但是您可以创建一个模板类或函数来包装它。在任何情况下,都必须遵从3个向量或计算线性存储中元素的展平索引

考虑到不要在实验中使用第三部分矩阵库,如Eigen

您编写代码不是为了生产,而是为了研究。特别是,您的研究正是关于算法的性能。在这种情况下,我不建议绝对使用第三方库,比如Eigen。当然,这在很大程度上取决于你愿意收集什么样的算法速度指标,但例如,艾根会在幕后做很多事情,这会对你的实验产生巨大的影响。由于您很难控制这些看不见的优化,这些库的特性可能会导致您对算法得出错误的结论

算法性能与大o表示法


通常情况下,算法的性能是通过使用一个不考虑实际花费的时间、硬件速度或编程语言特性等因素来分析的。Adam Drozdek的C++中的数据结构和算法可以提供更多的细节。

TIPS:TyPulf STD::向量T3DMatL.;使用t3DMatrix=std::vector;因为C++17左右是better@skratchi.at来自C++11,相关:使用实际的矩阵库。但是,使用连续内存的一个主要缺点是,对大量内存的请求可能会失败。即使请求相对适中的30-40MB数据块,也常常会失败。内存很快就会变得碎片化,大的块分配可能会失败。需要注意的是,64位寻址并不是什么大问题,即使实际减少到48位,物理内存也可以使用页表拼凑起来。这取决于实现,但当数据块变大时,libstdc++的默认分配器将切换到基于mmap的分配,完全避免内存碎片。其大的概念是动态的和可配置的,但从128kB开始。很可能其他实现也有类似的机制。