When do you prefer using std::list<T> instead of std::vector<T>?

末鹿安然 提交于 2019-11-26 23:00:53

问题


I've never used std::list<T> myself. I was wondering when people use it when we already have std::vector<T> which is just like arrays with contiguous memory. std::vector seems like a perfect choice when we need sequential container!

So my question is

  • When exactly do you prefer std::list over std::vector? and why exactly?
  • When do you prefer std::vector over std::list? and why?

If there is performance consideration, then please list them too with detail explanation/information.

If possible, quote some references also, to support your answer.


回答1:


Lists are better for inserting or deleting anywhere in the middle, vectors are better for inserting at the end.

Vectors are also better for accessing elements.

This is an artefact of the way they're implemented.

So, if a collection changes very little (compared to accesses) or the changes are concentrated at the end, I'd use a vector.

If the number of changes is substantial (compared to accesses) and they're not at the ends, I'd use a list.

By way of example, reading in a collection at program startup and hardly ever changing it (or if the changes are onlt adding to the end), this would be a good candidate for a vector.

On the other hand, a phone book application for a particularly popular and fickle rock star, I'd be looking towards a list. Actually I'd be looking toward a database connection but that was the best example I could come up with at short notice :-)

As to references, the latest C++0x draft states in part (23.3.4, lists):

A list is a sequence container that supports bidirectional iterators and allows constant time insert and erase operations anywhere within the sequence, with storage management handled automatically. Unlike vectors and deques, fast random access to list elements is not supported.

Section 23.3.5 (on vectors):

A vector is a sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time.




回答2:


So my question is: when exactly do you prefer std::list over std::vector?

When I need a sequential container in a performance-sensitive area and profiling shows std::list is faster.

So far, this has never happened to me.

(I might be tempted to try std::list first when I would have to store very big objects with lots of insertion/removal in the middle. However, in practice, I've never come across such a use-case.)




回答3:


There are a few trade-offs to be considered when choosing between std::list and std::vector. Also std::list is not about contiguous memory, it can be quite useful if you can't afford iterator invalidation or if you need amortized constant time insertion in the begin/middle/end.




回答4:


The only (few) times I preferred std::list is due to the list::splice member function. If you are shuffling around subranges within a list or between lists this operation can be significantly faster than using std::vector.




回答5:


I don't need to repeat the basics, but what I learned the hard way is that if insertion performance is relevant and you have "large" objects, then you should really consider a std::list, even if you're only inserting at the end. (Well, a list or possibly a vector of smart pointer / ptr_vector.)

We had some use cases where we had to build up collections of a priori unknown size of structs of multiple small std::string and using a std::vector totally killed insertion performance and added a non-neglible memory overhead.

The problem with std::vector in the unknown count insert scenario is:

  • Since the vector will always over allocate, you pay 50% space overhead worst case for typical implementations (A single vector of string, where an object has, e.g. 24 bytes (MSVC), given meagre 100,000 elements, could have a space overhead of 2MB. And it will multiply for larger objects with more string or other biggish members.)
  • Every time the vector has to reallocate, it has to copy all the objects around, and that ain't cheap if you have anything slighly complex. Obviously, move-semantics will help, but if the objects themselves are large, the repeated copy may still be relevant. It doesn't matter if the average amortized insertion time (at the end) is theoretically constant, if you copy all your objects muliple times during building up of the vector. You may notice this peformance hit.
  • Objects get large really quick: A struct of only two empty std::string already has non-moveable 48 bytes on MSVC.

This is not to bash std::vector, I still use it by default -- but know what to expect of your datastructures!




回答6:


In addition to other answers, node-base containers(list/associative containers) can provide strong exception guarantee.
Even if a container-mutating operation(for example insertion) throws an exception, all the pointers/references/iterators to the elements remain valid.
However, linear-memory(piecewise contiguous memory cell) containers can provide only basic guarantee. When an insertion throws, even if the insertion isn't actually executed, pointers/references/iterators may be invalidated (though the container itself can be destructed safely).




回答7:


You use std::list when you need to frequently modify the sequence in other places than the front or back. The overhead of such operations is large in std::vector in comparision std::list.




回答8:


Use a list when its invalidation semantics and performance characteristics match your requirements.

List can insert/erase/splice anywhere in O(1), and this doesn't invalidate any iterators. Vector is O(n) for insert/erase except at the end, and even then only for insert if size < capacity; vector can't splice. Performance is even more subtle than this, with the caching locality mentioned in another answer, for example.




回答9:


std::list is my preferred almost exclusively for but one property that vector does not share, and that's knowing my pointers into a list will always be valid. Because of this, I can use this to contain all the instances of whatever asset I need in a single area, while also loaning out references to other objects to use. Best example I could think of would be an image loader that only keeps one copy of pixels in memory, while loaning out pointers to multiple entities so they can all draw from it.

All vector has going for it is O(1) access time. While that sounds like a huge asset, in practice I have very rarely ever needed to access items in a data structure outside stepping from 'first' to 'last'




回答10:


Some would say that you should, arguably, never ever ever use linked list in your code again. ;)

One issue is that vectors have much better locality of reference, and the big performance gains resulting from this will then, in many cases, outweigh the advantages of more (algorithmically) efficient operations for things like delete and insert in a linked list.

(See the blog post lined above for more discussion of this specific issue, with benchmarks and so on.)

So, often a std::vector will outperform std::list, even if you are doing a certain number of operations for which a list would be more natural (e.g. arbitrary element deletion, insert at arbitrary position, or splice).

But note that, even when you do do lots of these kinds of operations, you may be better off 'hosting' your list within the contiguous buffer of a std::vector.

I discuss this in more detail in this blog post, with some diagrams and code examples: http://upcoder.com/12/vector-hosted-lists/

In the specific case when you need to delete arbitrary elements, but don't need to insert at arbitrary positions or splice, a good alternative to a full blown linked list can be to just mark entries as 'dead' and skip over these dead entries during iteration.




回答11:


You should use a list when you're doing a lot of deletions / insertions.

Vector can be used if the total size of elements does not change a lot, and if you do some swapping.



来源:https://stackoverflow.com/questions/5056973/when-do-you-prefer-using-stdlistt-instead-of-stdvectort

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!