93

Since

  1. they are both contiguous memory containers;
  2. feature wise, deque has almost everything vector has but more, since it is more efficient to insert in the front.

Why whould anyone prefer std::vector to std::deque?

Martin G
  • 17,357
  • 9
  • 82
  • 98
Leon
  • 8,151
  • 11
  • 45
  • 51
  • 3
    The Visual C++ implementation of `std::deque` has a very small maximum block size (~16 bytes, if I recall correctly; maybe 32), and as such doesn't perform very well for realistic applications. A `deque` where `sizeof(T) > 8` (or 16? It's a small number) has about the same performance characteristics as a `vector`, where each element is allocated dynamically. Other implementations have different maximum block sizes, so writing code that has relatively the same performance characteristics on different platforms is difficult with `deque`. – James McNellis Mar 17 '11 at 21:08
  • 22
    Deque is not a continuous memory container. – Mohamed El-Nakeep Apr 21 '14 at 01:49
  • @ravil No, that is the duplicate, pointing at this question. –  Oct 29 '14 at 16:36
  • I wanted to edit "deque has almost vector has but more" so it would make sense, but I'm not sure what it's supposed to mean. – DCShannon Jul 06 '15 at 18:13
  • 2
    hard to believe a question with an unfixed blatant factual error was sitting at a balance of 34 votes – underscore_d Dec 16 '15 at 21:33
  • 2
    @underscore_d that's why it's a question. Different story if it was an answer ;) – Assimilater Aug 12 '16 at 23:39
  • Pretty good explanation by Bo Qian: [Vector Vs Deque - I](https://www.youtube.com/watch?v=Ct8ykaKrKOA&list=PL5jc9xFGsL8E_BJAbOw_DH6nWDxKtzBPA&index=6) and [Vector Vs Deque - II](https://www.youtube.com/watch?v=pW2jDTf82IM&list=PL5jc9xFGsL8E_BJAbOw_DH6nWDxKtzBPA&index=7) – ani627 Jan 16 '17 at 17:46

10 Answers10

129

Elements in a deque are not contiguous in memory; vector elements are guaranteed to be. So if you need to interact with a plain C library that needs contiguous arrays, or if you care (a lot) about spatial locality, then you might prefer vector. In addition, since there is some extra bookkeeping, other ops are probably (slightly) more expensive than their equivalent vector operations. On the other hand, using many/large instances of vector may lead to unnecessary heap fragmentation (slowing down calls to new).

Also, as pointed out elsewhere on StackOverflow, there is more good discussion here: http://www.gotw.ca/gotw/054.htm .

Community
  • 1
  • 1
phooji
  • 10,086
  • 2
  • 38
  • 45
44

To know the difference one should know how deque is generally implemented. Memory is allocated in blocks of equal sizes, and they are chained together (as an array or possibly a vector).

So to find the nth element, you find the appropriate block then access the element within it. This is constant time, because it is always exactly 2 lookups, but that is still more than the vector.

vector also works well with APIs that want a contiguous buffer because they are either C APIs or are more versatile in being able to take a pointer and a length. (Thus you can have a vector underneath or a regular array and call the API from your memory block).

Where deque has its biggest advantages are:

  1. When growing or shrinking the collection from either end
  2. When you are dealing with very large collection sizes.
  3. When dealing with bools and you really want bools rather than a bitset.

The second of these is lesser known, but for very large collection sizes:

  1. The cost of reallocation is large
  2. The overhead of having to find a contiguous memory block is restrictive, so you can run out of memory faster.

When I was dealing with large collections in the past and moved from a contiguous model to a block model, we were able to store about 5 times as large a collection before we ran out of memory in a 32-bit system. This is partly because, when re-allocating, it actually needed to store the old block as well as the new one before it copied the elements over.

Having said all this, you can get into trouble with std::deque on systems that use "optimistic" memory allocation. Whilst its attempts to request a large buffer size for a reallocation of a vector will probably get rejected at some point with a bad_alloc, the optimistic nature of the allocator is likely to always grant the request for the smaller buffer requested by a deque and that is likely to cause the operating system to kill a process to try to acquire some memory. Whichever one it picks might not be too pleasant.

The workarounds in such a case are either setting system-level flags to override optimistic allocation (not always feasible) or managing the memory somewhat more manually, e.g. using your own allocator that checks for memory usage or similar. Obviously not ideal. (Which may answer your question as to prefer vector...)

CashCow
  • 30,981
  • 5
  • 61
  • 92
34

I've implemented both vector and deque multiple times. deque is hugely more complicated from an implementation point of view. This complication translates to more code and more complex code. So you'll typically see a code size hit when you choose deque over vector. You may also experience a small speed hit if your code uses only the things the vector excels at (i.e. push_back).

If you need a double ended queue, deque is the clear winner. But if you're doing most of your inserts and erases at the back, vector is going to be the clear winner. When you're unsure, declare your container with a typedef (so it is easy to switch back and forth), and measure.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 3
    Question -- has the committee considered adding a hybrid of the two (say, a "deck") to C++? (i.e. a double-ended `vector`.) I have written an implementation linked to below in [my answer](http://stackoverflow.com/a/11836866/541686). It can be as fast as a `vector` but much more widely applicable (e.g., when making a fast queue). – user541686 Aug 26 '13 at 09:04
5

std::deque doesn't have guaranteed continuous memory - and it's often somewhat slower for indexed access. A deque is typically implemented as a "list of vector".

Erik
  • 88,732
  • 13
  • 198
  • 189
  • 15
    I don't think a "list of vector" is correct: my understanding was that most implementations were a "vector of pointers to arrays," though it depends on your definition of "list" (I read "list" as "linked list," which wouldn't meet the complexity requirements.) – James McNellis Mar 17 '11 at 21:12
2

According to http://www.cplusplus.com/reference/stl/deque/, "unlike vectors, deques are not guaranteed to have all its elements in contiguous storage locations, eliminating thus the possibility of safe access through pointer arithmetics."

Deques are a bit more complicated, in part because they don't necessarily have a contiguous memory layout. If you need that feature, you should not use a deque.

(Previously, my answer brought up a lack of standardization (from the same source as above, "deques may be implemented by specific libraries in different ways"), but that actually applies to just about any standard library data type.)

pattivacek
  • 5,617
  • 5
  • 48
  • 62
  • 5
    `std::deque` is no less standardized than `std::vector`. I don't believe the complexity requirements for `std::deque` can be met with contiguous storage. – Jerry Coffin Mar 17 '11 at 22:17
  • 1
    Perhaps my phrasing was poor: although it is true that standardization is not thorough, as I understand it, vectors are standardized to be a conitugous sequence, and deques are not. That seems to be the one deciding factor. – pattivacek Mar 18 '11 at 14:48
  • vector wasn't originally required to be contiguous either -- that was added later. vector is more limited, and generally a bit faster. deque gives up a bit of speed to allow slightly greater flexibility. – Jerry Coffin Mar 18 '11 at 14:51
  • 1
    @JerryCoffin: Which complexity requirements of `deque` can't met with contiguous storage? – user541686 Oct 12 '12 at 01:55
  • 1
    @Mehrdad: To be honest, I don't remember what I had in mind. I haven't looked at that part of the standard recently enough that I feel comfortable stating categorically that my earlier comment was wrong, but looking at it right now, I can't think of how it would be right either. – Jerry Coffin Oct 12 '12 at 03:23
  • 3
    @JerryCoffin: The complexity requirements are actually trivial: you could allocate a large array and start pushing your sequence from the middle outwards (I guess this is what Mehrdad implementation does), then reallocate when you get to the ends. The problem with this approach is that it does not satisfy one of the requirements of `deque`, namely that insertion at the ends shall not invalidate *referenced* to the existing elements. This requirement implies discontinuous memory. – Yakov Galka Oct 20 '12 at 17:47
  • @ybungalobill you could reallocate only when full and alternatively shift the data towards the middle if it hits one end (you'd have to move it anyway) but it would invalidate references, as would a reallocation if you did actually get full. For a FIFO queue you can use a vector and implement as a ring. (Fixed-length FIFO queue) – CashCow Oct 29 '15 at 18:03
  • @CashCow: When shifting, just be careful to guarantee O(1) amortized insertion at both ends. – Yakov Galka Oct 29 '15 at 19:48
1

Note that vector memory is re-allocated as the array grows. If you have pointers to vector elements, they will become invalid.

Also, if you erase an element, iterators become invalid (but not "for(auto...)").

Edit: changed 'deque' to 'vector'

Pierre
  • 4,114
  • 2
  • 34
  • 39
  • -1: Insert and erase at begin or end does NOT invalidate references and pointers to other elements. (Although insert and erase in the middle does) – Sjoerd Jul 09 '20 at 15:55
  • @Sjoerd I changed it to 'vector'. – Pierre Jul 09 '20 at 19:07
  • 1
    *Pointer stability* of `std::deque` on `push_back()` and `emplace_back()` is one reason I'd consider it over `std::vector`, for example when inserting pointers to those elements into a map as values. – ddevienne May 06 '21 at 15:29
0

You woudn't prefer vector to deque acording to these test results (with source).

Of course, you should test in your app/environment, but in summary:

  • push_back is basically the same for all
  • insert, erase in deque are much faster than list and marginally faster than vector

Some more musings, and a note to consider circular_buffer.

Nick Westgate
  • 3,088
  • 2
  • 34
  • 41
0

On the one hand, vector is quite frequently just plain faster than deque. If you don't actually need all of the features of deque, use a vector.

On the other hand, sometimes you do need features which vector does not give you, in which case you must use a deque. For example, I challenge anyone to attempt to rewrite this code, without using a deque, and without enormously altering the algorithm.

BenGoldberg
  • 415
  • 3
  • 6
  • Actually, on the same series of `push_back` and `pop_back` operations, `deque` is always at least 20% faster than `vector` in my tests (gcc with O3). I guess that's why `deque` is the standard choice for things like `std::stack`... – igel Apr 22 '20 at 18:59
0

A deque is a sequence container which allows random access to it's elements but it is not guaranteed to have contiguous storage.

Sean
  • 5,290
  • 2
  • 24
  • 21
0

I think that good idea to make perfomance test of each case. And make decision relying on this tests.

I'd prefer std::deque than std::vector in most cases.

George Gaál
  • 1,216
  • 10
  • 21
  • 1
    The question, if any can be distilled from among the factual errors and missing words, was _why_ someone would prefer `vector`. We can infer that _why not_ is a corollary. Saying that you prefer `deque`, for unknown reasons, from unspecified tests, is not an answer. – underscore_d Jun 27 '16 at 19:22