阅读this question并查看一些results here之后,似乎应该完全避免使用C ++中的列表。我总是希望链接列表是我只需要迭代所有内容的情况下的首选容器,因为插入是指针操作的问题,并且永远不需要重新分配。
显然,由于“缓存局部性”,列表的迭代速度非常慢,因此必须使用更少的保留内存或更快的添加(从第二个链接看起来速度不是那么快)的任何好处都不会似乎值得。
话虽如此,从表现的角度来看,我应该何时使用std::list
而不是std::deque
,或者如果可能的话std::vector
?
另外,std::forward_list
还会有很多缓存未命中吗?
答案 0 :(得分:15)
从性能角度来看,我应该何时使用
std::list
从表现的角度来看,很少。想到的唯一情况是,如果您有许多列表需要拆分并加入以形成其他列表;链接列表可以在不分配内存或移动对象的情况下执行此操作。
list
的真正好处是稳定性:元素不需要是可移动的,迭代器和引用永远不会失效,除非它们引用已被删除的元素。
另外,
std::forward_list
还会有很多缓存未命中吗?
是;它仍然是一个链表。
答案 1 :(得分:14)
std::list
在一些极端情况下非常有用。
但是,C ++顺序容器的一般规则是“如果您的算法兼容,请使用std::vector
。如果您的算法不兼容,请修改算法,以便使用std::vector
。”
存在例外,这是尝试详尽列出std::list
更好选择的原因:
当您需要(A)插入容器的中间并且(B)时,您需要内存中的每个对象位置都是稳定的。通常可以通过包含指向元素的指针的非稳定容器来移除要求(B),因此这不是使用std::list
的强有力理由。
当你需要(A)在容器(B)中间插入或删除比你需要迭代容器更多的数量级。这也是一个极端的极端情况:为了找到要从list
删除的元素,通常需要迭代!
导致
您需要(A)在容器中间插入或删除,(B)所有其他元素的迭代器保持有效。这最终成为案例1和案例2的隐藏要求:当你没有持久迭代器时,很难删除或插入比迭代更频繁,并且迭代器和对象的稳定性高度相关。
最后一种情况,拼接的情况曾经是使用std::list
的理由。
回到C ++ 03,std::list::splice
的所有版本都可以(理论上)在O(1)时间内完成。但是,splice
的极其有效的形式要求size
是O(n)操作。 C ++ 11要求size
上的list
为O(1),因此splice
的极端效率仅限于“拼接整个其他列表”和“自我”拼接子列表“案例。在单个元素拼接的情况下,这只是插入和删除。在子范围拼接的情况下,代码现在必须访问拼接中的每个节点才对其进行计数,以便将size
维持为O(1)(自拼接除外) )。
因此,如果您只进行整个 - list
拼接或自列表子splice
s,list
可以比其他非列表容器更快地执行这些操作。< / p>
答案 2 :(得分:7)
std::list
可以提供的最大改进是当您将一个或多个元素从一个列表的中间移动到另一个列表中时。此splice
操作在list
上非常有效,但可能涉及在vector
等随机访问容器中分配和移动项目。也就是说,这很少出现,而且大部分时间vector
在性能和简单性方面都是最好的容器。
如果您怀疑容器选择存在性能问题,请始终对代码进行概要分析。
答案 3 :(得分:6)
当您经常在容器中间添加/删除项目see also时,您选择了std::list
而不是std::deque
和std::vector
(以及其他连续的内存容器)。< / p>