我应该使用deque或vector在c++中存储巨大的deque吗?

Should I use a deque or vector to store huge deques in C++?

本文关键字:deque 巨大 存储 vector 我应该 c++      更新时间:2023-10-16

假设我有40个巨大的队列,每个队列存储用户定义类型的数据。40并不是很多,但是deques本身是巨大的(因此我选择使用deques而不是向量)。我的问题是,如果我想要一个容器来存放这40个deque,这个容器应该是矢量还是deque?

如果我选择一个向量来包含我的大deque,这会使向量在内存中很大,或者向量的元素只是指向deque ?如果包含向量变得巨大,作为存储40个巨大的deque的结果,那么我需要使用deque,而不是避免连续的内存相关的问题,我遇到当我最初选择使用deque用户定义类型容器?

例子;

class myClass {
  // lots of data members resulting in large class object
}
int main(){
  std::deque<myClass> foo;
  for(int i=0, i<10000000, i++){
    myClass classObject;
    foo.push_back(classObject);
  }
}

现在我们有了一个deque,其中包含了1000000个元素,其中包含了我们的类对象。假设我创建了40个这样的deque。

如果我想为这40个deque设置一个容器我应该这样做吗;

std::vector< std::deque<myClass> > bar

或者我应该这样做;

std::deque< std::deque<myClass> > bar

是否vector的元素仅仅指向deque

对于你问的问题:不。对于你的问题:是的。

vector<deque<T>>中,向量元素是实际的deque对象本身,而不是指向它们的指针。但是std::deque对象非常瘦,因为它们反过来又有指向双端数据结构的指针,其中包含队列的内容。

使用vector<deque<T>>(甚至vector<vector<T>>),您的40个数据集将不会在内存中彼此连续存储——只有当内部容器像std::array一样没有分配时,所有容器的数据才会存储在一起。

另一方面,如果你真的希望你的向量元素是指向deque对象的指针,那么你可以使用vector<unique_ptr<deque<T>>>

容器将其实际数据存储在Free store(堆)中的外部存储器中。因此,使用std::deque来存储大约40个deques没有任何好处,因为它只存储deques内部管理数据,只有几个字节。所以我将使用std::vector

如果数字正好是 40,那么我会考虑std::array

一般来说,正如教皇斯特鲁普自己所说,

我不知道你的数据结构,但我打赌std::vector可以打败它

意味着通常你想要线性结构,而不是链表或其他任何东西,因为通常"丰富"的计算环境(例如:pc等)非常擅长优化线性访问。

然而,如果这些携带数据的类对象都很大,我的意思是"大约和CPU缓存条目一样大",那么这不会有太大的区别。如果数据结构合适,可以使用deque(反正大多数时候都是线性的);另外,如果事先知道的话,还可以告诉它预先为1000000个元素分配内存,方法是将这个数字传递给构造函数。

无论如何,你使用的内存结构不会对你需要多少内存产生重大影响。您将需要40 * 10000000个元素。就是这样。如果这超过了你的内存,你需要获得更多的内存,或者编写一个更好的算法。

让我们考虑一下这些选项,我认为它们是:

  • std::vector<std::deque>
  • std::vector<std::deque *>
  • std::deque<std::deque>
  • std::deque<std::deque *>

container<std::deque> &container<std::deque *>是所有成员将连续存储(deque大部分是连续的,但不是完全连续的)。这意味着使用container<std::deque>访问内容通常不会缓存丢失,但实际数据通过指针和will存储在对象中。而对于container<std::deque *>,容器中的值将缓存丢失,然后在访问数据时再次缓存。

容器应该是deque还是vector取决于您是否有可能将其重新增长,以及您是否关心可变速率迭代。也就是说,vector是连续的,因此在线性迭代时不会缓存丢失,这对于deque来说是不保证的,当它跳转到子容器时,它可能会破坏预取。

编辑:我忘了提到为什么你可能更喜欢缓存丢失而不是连续性,答案是碎片。对于庞大的数据集,您给堆施加了很大的压力,增加了分配失败的机会,即使有足够的内存来存储它,因为内存分散在堆中,自定义分配器对于碎片和缓存丢失来说是一个潜在的两全美的选择。