1

I just wanted to know how deque is implemented and how are the basic operations like push_front and random access operator are provided in that implementation.

  • 1
    From [this `std::deque` reference](https://en.cppreference.com/w/cpp/container/deque): "typical implementations use a sequence of individually allocated fixed-size arrays". In short, it's a list of arrays. – Some programmer dude May 27 '19 at 07:45
  • 1
    Possible duplicate of [What really is a deque in STL?](https://stackoverflow.com/questions/6292332/what-really-is-a-deque-in-stl) – Silvano Cerza May 27 '19 at 07:52
  • 2
    @Someprogrammerdude if it was implemented as a "list" of arrays, the constant random access wouldn't be possible. Typically it is an array of pointers to arrays with data. – Dmitry Kuzminov May 27 '19 at 07:53

1 Answers1

3

I just wanted to know how deque is implemented

It's always a good to have an excuse for doing ASCII art:

+-------------------------------------------------------------+                       
| std::deque<int>                                             |                       
|                                                             |                       
|  subarrays:                                                 |                       
| +---------------------------------------------------------+ |                       
| |           |           |           |         |           | |                       
| | int(*)[8] | int(*)[8] | int(*)[8] |int(*)[8]|int(*)[8]  | |                       
| |           |           |           |         |           | |                       
| +---------------------------------------------------------+ |                       
|                        /            \                       |                       
|                       /              \                      |                       
|                      /                \                     |                       
|                     /                  \                    |                       
|                    /                    \                   |                       
|                   /                      \                  |                       
|                  /                        \                 |                       
|                 /                          \                |                       
|                -                            -               |                       
|               +------------------------------+              |                       
|               | ?, ?, 42, 43, 50, ?, ?, ?, ? |              |                       
|               +------------------------------+              |                       
|                                                             |
| additional state:                                           |                       
|                                                             |                       
| - pointer to begin of the subarrays                         |                       
| - current capacity and size                                 |                       
| - pointer to current begin and end                          |                       
+-------------------------------------------------------------+                       

how are the basic operations like push_front and random access operator are provided in that implementation?

First, std::deque::push_front, from libcxx:

template <class _Tp, class _Allocator>
void
deque<_Tp, _Allocator>::push_front(const value_type& __v)
{
    allocator_type& __a = __base::__alloc();
    if (__front_spare() == 0)
        __add_front_capacity();
    __alloc_traits::construct(__a, _VSTD::addressof(*--__base::begin()), __v);
    --__base::__start_;
    ++__base::size();
}

This obviously checks whether the memory already allocated at the front can hold an additional element. If not, it allocates. Then, the main work is shifted to the iterator: _VSTD::addressof(*--__base::begin()) goes one location before the current front element of the container, and this address is passed to the allocator to construct a new element in place by copying v (the default allocator will definitely do a placement-new).

Now random access. Again from libcxx, std::deque::operator[] (the non-const version) is

template <class _Tp, class _Allocator>
inline
typename deque<_Tp, _Allocator>::reference
deque<_Tp, _Allocator>::operator[](size_type __i) _NOEXCEPT
{
    size_type __p = __base::__start_ + __i;
    return *(*(__base::__map_.begin() + __p / __base::__block_size) + __p % __base::__block_size);
}

This pretty much computes an index relative to some start index, and then determines the subarray and the index relative to the start of the subarray. __base::__block_size should be the size of one subarray here.

lubgr
  • 35,985
  • 3
  • 62
  • 111