想象一下,我有40个巨大的deques,每个deques存储用户定义类型的数据。 40并不是那么多,但是deques本身是巨大的(因此我选择使用deques而不是矢量)。我的问题是,如果我想要这个40个deques的容器,那个容器应该是vector还是deque?
如果我选择一个向量来包含我的巨大deques会使向量在内存中变大,还是向量的元素只是指向deques?如果由于存储了40个巨大的deques而包含的向量变得很大,那么我是否需要使用deques来避免我在最初选择对用户定义的类型容器使用deques时遇到的连续的内存相关问题? / p>
实施例
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);
}
}
我们现在有一个包含1000000个元素的双端队列,其中包含我们的类对象。想象一下,我创造了40个这样的deques。
现在,如果我想要这个40个deques的容器,我应该这样做;
std::vector< std::deque<myClass> > bar
或者我应该这样做;
std::deque< std::deque<myClass> > bar
答案 0 :(得分:4)
向量的元素只是指向deques
你问的问题:没有。 对于你的意思:是的。
在vector<deque<T>>
中,向量元素本身就是实际的deque
对象,而不是指向它们的指针。但std::deque
对象非常薄,因为它们反过来指向双端数据结构的指针,其中deque的内容所在。
使用vector<deque<T>>
(或甚至vector<vector<T>>
),您的40个数据集将不会在内存中相互存储 - 只有当内部容器像std::array
那样无分配时才会存在所有容器的数据都存储在一起。
另一方面,如果你真的希望你的向量元素成为deque
个对象的指针,那么你可以使用vector<unique_ptr<deque<T>>>
。
答案 1 :(得分:1)
容器将实际数据存储在Free Store(堆)的外部存储中。因此,使用std::deque
仅存储40-ish deques 没有任何好处,因为它只会存储 deques &#39;内部管家数据只有几个字节。所以我会使用std::vector
。
如果数字完全 40
那么我会考虑std::array
。
答案 2 :(得分:0)
一般来说,正如他的圣洁Stroustrup自己说的那样,
我不知道您的数据结构,但我打赌
std::vector
可以击败它
意思是通常你想要线性结构,而不是可能是链接列表或其他任何东西的东西,因为通常&#34;富有&#34;计算环境(阅读:PC等)非常擅长优化线性访问。
但是,如果每个这些携带数据的类对象都很大,我的意思是&#34;大约和CPU缓存条目一样大,那么这就不行了发挥巨大作用。如果这是正确的数据结构,那么请使用双端队列(无论如何,它在大多数情况下是线性的);另外,如果您事先知道,也可以告诉它预先为1000000个元素分配内存,方法是将该数字传递给构造函数。
无论如何,您使用的内存结构不会对您有效需要的内存产生重大影响。你需要40 * 10000000个元素。就是这样。如果这比您拥有的内存更多,那么您需要获得更多内存,或者编写更好的算法。
答案 3 :(得分:0)
让我们考虑选项,因为我看到它们是:
std::vector<std::deque>
std::vector<std::deque *>
std::deque<std::deque>
std::deque<std::deque *>
container<std::deque>
&amp;之间的差异container<std::deque *>
是所有成员将被连续存储(deque主要但不完全连续)。
这意味着使用container<std::deque>
访问内容通常不会缓存未命中,但实际数据通过指针和将存储在对象中。而使用container<std::deque *>
时,容器中的值将缓存未命中,然后在访问数据时再次缓存。
容器应该是双端队列还是向量取决于您是否可能将其重新发展以及您是否关心可变速率迭代。即一个向量在设置后是连续的,因此在线性迭代时不会缓存未命中,这不能保证deque,当它跳过子容器时,它可能会破坏预取。
编辑:我忘了提到为什么你可能更喜欢缓存错过连续性,答案是碎片化。使用庞大的数据集会给堆上带来很大的压力,即使有足够的内存来存储它也会增加分配失败的可能性,因为内存分散在堆中,自定义分配器是两个世界中最好的选择。碎片和缓存未命中。