Я просто хотел узнать, как реализован deque
Всегда хорошо иметь оправдание для выполнения ASCII-искусства:
+-------------------------------------------------------------+
| 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 |
+-------------------------------------------------------------+
какбазовые операции, такие как push_front
и оператор произвольного доступа, предусмотрены в этой реализации?
Сначала std::deque::push_front
из 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();
}
Это, очевидно, проверяет, является липамять, уже выделенная спереди, может содержать дополнительный элемент.Если нет, он выделяет.Затем основная работа переносится на итератор: _VSTD::addressof(*--__base::begin())
идет на одну позицию перед текущим передним элементом контейнера, и этот адрес передается распределителю для создания нового элемента на месте путем копирования v
(распределитель по умолчаниюопределенно сделаю размещение - new
).
Теперь произвольный доступ.Снова из libcxx, std::deque::operator[]
(версия не const
) равна
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);
}
. Это в значительной степени вычисляет индекс относительно некоторого начального индекса, а затем определяет подмассив и индекс относительно началаподмассива.__base::__block_size
здесь должно быть размером с один подмассив.