Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there ever a reason to use std::list? [duplicate]

After having read this question and looking at some results here, it seems like one should altogether completely avoid lists in C++. I always expected that linked lists would be the containers of choice for cases where I only need to iterate over all the contents because insertion is a matter of pointer manipulation and there is never a need to reallocate.

Apparently, because of "cache locality," lists are iterated over very slowly, so any benefit from having to use less reserve memory or faster addition (which is not that much faster, it seems, from the second link) doesn't seem worth it.

Having said that, when should I, from a performance standpoint, use std::list over std::deque or, if possible, std::vector?

On a side note, will std::forward_list also have lots of cache misses?

like image 603
VF1 Avatar asked Aug 26 '13 16:08

VF1


People also ask

Should I use std::list?

Consider using std::list if: You need to store many items but the number is unknown. You need to insert or remove new elements from any position in the sequence. You do not need efficient access to random elements.

When should we use a list in C++?

If you insert, remove, and move elements often in the middle of a container, consider using a list. Lists provide special member functions to move elements from one container to another in constant time.

Is std::list double linked?

std::list is a container that supports constant time insertion and removal of elements from anywhere in the container. Fast random access is not supported. It is usually implemented as a doubly-linked list.


1 Answers

std::list is useful in a few corner cases.

However, the general rule of C++ sequential containers is "if your algorithm are compatible, use std::vector. If your algorithms are not compatible, modify your algorithms so you can use std::vector."

Exceptions exist, and here is an attempt to exhaustively list reasons that std::list is a better choice:

  1. When you need to (A) insert into the middle of the container and (B) you need each objects location in memory to be stable. Requirement (B) can usually be removed by having a non-stable container consisting of pointers to elements, so this isn't a strong reason to use std::list.

  2. When you need to (A) insert or delete in the middle of the container (B) orders of magnitude more often than you need to iterate over the container. This is also an extreme corner case: in order to find the element to delete from a list, you usually need to iterate!

Which leads to

  1. you need (A) insert or delete in the middle of the container and (B) have iterators to all other elements remain valid. This ends up being a hidden requirement of case 1 and case 2: it is hard to delete or insert more often than you iterate when you don't have persistant iterators, and the stability of iterators and of objects is highly related.

  2. the final case, is the case of splicing was once a reason to use std::list.

Back in C++03, all versions of std::list::splice could (in theory) be done in O(1) time. However, the extremely efficient forms of splice required that size be an O(n) operation. C++11 has required that size on a list be O(1), so splice's extreme efficiency is limited to the "splicing an entire other list" and "self-splicing a sublist" case. In the case of single element splice, this is just an insert and delete. In the case of sub range splice, the code now has to visit every node in the splice just to count them in order to maintain size as O(1) (except in self-splicing).

So, if you are doing only whole-list splices, or self-list subrange splices, list can do these operations much faster than other non-list containers.

like image 199
Yakk - Adam Nevraumont Avatar answered Oct 13 '22 00:10

Yakk - Adam Nevraumont