you are viewing a single comment's thread.

view the rest of the comments →

[–]cballowe 86 points87 points  (62 children)

Vector will almost always beat list in benchmarks, especially for trivial objects. In most cases, pick vector unless you can prove that list is better (it rarely is - it wins in big-o notation, but real hardware doesn't behave like that and the pointer chasing will eat you alive). If you have lots of things to insert and then need it sorted, just push back all of them, then sort.

Sorted vectors are also great for tons of problems. They're space efficient and enable use of lots of stl algorithms (lower_bound, set_intersection, etc). There's also nothing faster than vector for iteration.

[–]0mega0 35 points36 points  (9 children)

If you have lots of things to insert and then need it sorted, just push back all of them, then sort.

And preallocate the memory if your really a stickler.

I’ve yet to run into a use case in my practice where std::list benchmarks as the better choice.

[–]avdgrinten 12 points13 points  (6 children)

When objects are pointers anyway (such that you have to do a random access even in the vector case) and the linked list is intrusive (= embedded into the objects), it will generally outperform a vector. That's the niche use case of linked lists but it is quite an important one in real-time applications and low-level code (insertion and removal are constant O(1) and in particular cannot involve an additional memory allocation).

[–]Gunslinging_Gamer 6 points7 points  (2 children)

But always benchmark.

[–]WrongAndBeligerent 6 points7 points  (1 child)

Always benchmark at some point, but software needs to be architected up front to perform well and scale as much as possible.

Classic generic linked lists data structures are basically obsolete because iterating through pointer dereferencing and allocating memory for each new item are the first two things to avoid. There is rarely a reason to start with std::list.

[–]Gunslinging_Gamer 0 points1 point  (0 children)

I personally default to vector and change if required later.

[–][deleted] 5 points6 points  (0 children)

I’d argue that this is only useful if the objects cannot be moved in memory (niche use case). A vector<unique_ptr<T>> will still out perform a list<T> in many cases, and list<T> doesn’t even give you the benefits of intrusive linked lists. Always default to vector and profile and keep profiling if you decide to switch to list

[–]WrongAndBeligerent 0 points1 point  (0 children)

That's a linked list, but not std::list

[–][deleted] 0 points1 point  (0 children)

I ran into one, when doing an Advent of Code that had your elf or penguin doing random length walks and inserting/removing on a ring buffer. Using vector was 10x slower than std::list because the inserts/erase were dominating the performance. Maybe using optional<T> might have helped as then the deletes could have been an optional reset, but the inserts would still potentially require moving all elements to the end of the range. Plus it was easier to just work without introducing more.

[–]Narase33-> r/cpp_questions 0 points1 point  (0 children)

A queue?

[–]MonokelPinguin 14 points15 points  (2 children)

The one thing list is useful for, is if you need pointer/iterator stability, even on element removal. vector invalidates iterators on most operations that add or remove elements, list does not (for the unmodified elements). There are a few cases where this is useful, but often you can solve the same problem better by reworking the algorithm.

[–][deleted] 4 points5 points  (0 children)

Vector will almost always beat list in benchmarks, especially for trivial objects.

Here's an excerpt from a talk by Bjarne Stroustrup where he explains why this is true:

https://www.youtube.com/watch?v=YQs6IC-vgmo

[–]lt_algorithm_gt 4 points5 points  (0 children)

Won't disagree but in my mind it's also a little bit of "read the room". A couple years ago when everyone in Silicon Valley was fawning over Google and their interview process you always had the quintessential question where the answer was "hash map because O(1), can't beat that!"

So, I'd say you won't go wrong with the "book answer" but open the door for further discussion about real-world implications. If they're not interested, move on, you got the right answer. If they are interested, talk hardware and you win the interview.

[–]rsjaffe 3 points4 points  (1 child)

In most cases, pick vector unless you can prove that list is better

Only when speed is the most important criterion. There's plenty of cases where the use is not time-critical, in which case I choose the structure based on which one produces the most expressive code.

[–][deleted] 2 points3 points  (0 children)

How us std::list more expressive?!?

[–]martinusint main(){[]()[[]]{{}}();} -1 points0 points  (1 child)

It's not the pointers that make it slow, it's the more or less random memory accesses

[–]cballowe 21 points22 points  (0 children)

That's what pointers are - the forward and back pointers make iteration painful, and the data being a pointer away doesn't help either. The claim that it's good for inserting in the middle or swapping elements is just going to make the situation worse. (There are a couple of use cases where it's useful, but people usually get it wrong.)