当元素数量较少时,为什么向量优于列表? 在他的《C++程序设计语言》(第四版)中,Bjarne Stroustrup指出:
请注意,当元素数量较少时,为什么向量优于列表? 在他的《C++程序设计语言》(第四版)中,Bjarne Stroustrup指出:,c++,vector,linked-list,C++,Vector,Linked List,请注意,向量通常是(令人惊讶的是,除非您 了解机器架构)比列表更有效 小元素的短序列(即使对于insert()和erase()) 他没有进一步阐述这一点,因此我想知道为什么这是真的,以及这些序列的长度(即元素的数量)?我认为这是因为列表使用动态方法来扩展列表(可能指向下一个,以便您可以轻松地在特定位置插入,而无需重新排列内存)。然而,向量实际上是一个简单的数组,带有一些漂亮的糖衣,使其更易于使用(如果您使用正确的函数,边界问题的可选例外) 基本上,当你实例化一个向量时,它会分配一个T类型的小数组
向量
通常是(令人惊讶的是,除非您
了解机器架构)比列表更有效
小元素的短序列(即使对于insert()
和erase()
)
他没有进一步阐述这一点,因此我想知道为什么这是真的,以及这些序列的长度(即元素的数量)?我认为这是因为列表使用动态方法来扩展列表(可能指向下一个,以便您可以轻松地在特定位置插入,而无需重新排列内存)。然而,向量实际上是一个简单的数组,带有一些漂亮的糖衣,使其更易于使用(如果您使用正确的函数,边界问题的可选例外) 基本上,当你实例化一个向量时,它会分配一个T类型的小数组。当你最后推送一个新项目时,如果你还没有变得太大,它只会将值写入已经分配的空间。但是,当你添加到一个列表中时,它必须分配内存并将该位置存储在各个指针中(我在这里猜测,但链表就是这样工作的。)如果你知道向量有多大(或者你能猜得很好),这是非常有效的。但是,一旦你超过了它的底层数组的大小,它就必须为新扩展的数据结构重新分配内存,然后复制所有内容。这对于将向量增大到较大的大小来说是非常昂贵的。在我的脑海中,向量以指数形式增长,因此在多次失败后,故障数量会减少,但是还是很贵 …以及这些序列的大致长度 正确的答案是:你必须测量 这取决于您在容器中存储的内容、构造、复制和移动该类型的成本、大小以及您的访问和插入模式 它在不同的机器之间也会有所不同,可能在编译器之间也会有所不同
回答问题的第一部分: …所以我想知道为什么这是真的 在这种情况下,它是正确的原因是向量的连续且最小填充的内存布局与现代CPU的缓存子系统的协作比列表的要好得多
vector
- 您的循环可能类似于
for (size_t i=0; i < v.size(); ++i) {
其中,for (list::const_iterator i=l.begin(); i != l.end(); ++i) {
的每个连续值必须从内存中加载(通过上一个节点的指针)i
- 您的下一次访问(
)可能已在缓存中,但:*++i
- 无论缓存线中适合的值有多大,列表节点也会更少:至少会有两个指针(一个在单链表中)的开销。如果您的值与指针大小相同(我们讨论的是小值),则使用列表的缓存线中的值会增加三分之一,从而导致缓存未命中率增加三倍
- 还要注意,下一次迭代的推测性执行取决于加载一个值,而不是增加一个寄存器:这里的缓存未命中不仅本身较慢,而且还会暂停推测性执行
- 您的循环可能类似于
4n
秒,而这次我们只有5项“。具体细节将取决于实现。insert
和erase
不在vector
末尾的操作是最糟糕的操作。但是如果vector的大小很小,即使这些操作也可以在不做太多工作的情况下执行。简单操作的效率加上缓存一致性使它们变得很快呃,比你想象的要快。你假设向量更快,因为列表不需要重新排列内存?