STL 全部容器應用到了空間配置器,固然 deque 在 _Deque_base 中設置了 兩個空間配置器,一個負責緩衝區元素的空間配置,一個負責中控器map的指針空間配置:node
typedef simple_alloc<_Tp, _Alloc> _Node_alloc_type; //負責緩衝區元素空間配置
typedef simple_alloc<_Tp*, _Alloc> _Map_alloc_type; //負責中控器map的指針空間配置
固然能夠追溯下元素空間配置用的配置器是啥:函數
typedef typename _Base::allocator_type allocator_type; allocator_type get_allocator() const { return _Base::get_allocator(); }
我們看看 _Base::get_allocator() 在哪裏spa
typedef _Alloc allocator_type; allocator_type get_allocator() const { return allocator_type(); }
能夠知道,其實 _Base::get_allocator() 仍是默認的空間配置器 _Alloc;指針
deque 提供的 constructor 以下:code
//拷貝構造函數
deque(const deque& __x) : _Base(__x.get_allocator(), __x.size()) { uninitialized_copy(__x.begin(), __x.end(), _M_start); }
//真正的構造函數 deque(size_type __n, const value_type& __value, const allocator_type& __a = allocator_type()) : _Base(__a, __n) { _M_fill_initialize(__value); }
_Base(__a,__n)負責產生並安排好 deque 的結構,看一下_M_fill_initialized 在哪裏,以下,該函數將元素的初值設定穩當:blog
template <class _Tp, class _Alloc> void deque<_Tp,_Alloc>::_M_fill_initialize(const value_type& __value) { _Map_pointer __cur; __STL_TRY {
//爲每一個節點的緩衝區設定初值 for (__cur = _M_start._M_node; __cur < _M_finish._M_node; ++__cur) { uninitialized_fill(*__cur, *__cur + _S_buffer_size(), __value); }
//最後一個節點的設定稍有不一樣(由於尾端可能有備用空間,沒必要設初值) uninitialized_fill(_M_finish._M_first, _M_finish._M_cur, __value); }
//失敗就銷燬已經配置好的 STL_UNWIND(destroy(_M_start, iterator(*__cur, __cur))); }
也看一下_Base(__a,__n)如何設定deque結構,根據 typedef _Deque_base<_Tp, _Alloc> _Base,找到_Deque_base構造函數以下:內存
_Deque_base(const allocator_type&, size_t __num_elements) : _M_map(0), _M_map_size(0), _M_start(), _M_finish() { _M_initialize_map(__num_elements); }
初始化_M_map等,這裏就很少說了,找一下_M_initialize_map 函數element
template <class _Tp, class _Alloc> void _Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements) { //節點數 = 元素總的個數 / 緩衝區大小 再 + 1; size_t __num_nodes = __num_elements / __deque_buf_size(sizeof(_Tp)) + 1; //中控器大小,最少爲初始設定個數8個,最多「所需節點數 + 2」 _M_map_size = max((size_t) _S_initial_map_size, __num_nodes + 2); //配置具備_M_map_size個節點的map中控器 _M_map = _M_allocate_map(_M_map_size); //設置頭部和尾部 _Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2; _Tp** __nfinish = __nstart + __num_nodes; __STL_TRY { //爲中控器map中每一個節點配置緩衝區 _M_create_nodes(__nstart, __nfinish); } //失敗則撤銷操做並釋放空間 __STL_UNWIND((_M_deallocate_map(_M_map, _M_map_size), _M_map = 0, _M_map_size = 0)); //爲deque內的兩個迭代_M_start 和 _M_finish更新內容 _M_start._M_set_node(__nstart); _M_finish._M_set_node(__nfinish - 1); _M_start._M_cur = _M_start._M_first; //多配置一個節點,_M_cur指向多配置的節點起始處 _M_finish._M_cur = _M_finish._M_first + __num_elements % __deque_buf_size(sizeof(_Tp)); }
接下來是push_back()函數,push_back()函數首先判斷在緩衝區是否有兩個以上的元素備用空間,若是有則直接構造,沒有就調用push_back_aux()函數,先配置一塊新的緩衝區,而後設置新元素內容,而後更改迭代器 finish 狀態:get
void push_back(const value_type& __t) { //先判斷是否有備用空間 if (_M_finish._M_cur != _M_finish._M_last - 1) { construct(_M_finish._M_cur, __t); ++_M_finish._M_cur; } else //沒有就調用該函數進行配置新的空間,並設置finish狀態 _M_push_back_aux(__t); }
我們再來看一下_M_push_back() 和 _M_push_front()函數,_M_push_back()函數是當map尾部沒有多餘節點存儲指向新的緩衝區的新指針的時候,須要額外在尾部繼續開闢一個新的空間,來存放新的指針,同理,_M_push_front()函數在頭部開闢新的空間來存儲指針,固然要知足空間不足的前提。it
//當map尾部還剩下一個節點(節點存取指向緩衝區的指針)時,就必須從新換一個map,配置更大的,拷貝原來的,釋放原來的
void _M_reserve_map_at_back (size_type __nodes_to_add = 1)
{ if (__nodes_to_add + 1 > _M_map_size - (_M_finish._M_node - _M_map)) _M_reallocate_map(__nodes_to_add, false); } //同理,頭部也是該操做 void _M_reserve_map_at_front (size_type __nodes_to_add = 1) { if (__nodes_to_add > size_type(_M_start._M_node - _M_map)) _M_reallocate_map(__nodes_to_add, true); }
特別的,當map很大,須要開闢額外的新的一塊內存用來遷移map時,就會調用_M_reallocate_map來開闢新的內存,以下:
template <class _Tp, class _Alloc> void deque<_Tp,_Alloc>::_M_reallocate_map(size_type __nodes_to_add, bool __add_at_front) { size_type __old_num_nodes = _M_finish._M_node - _M_start._M_node + 1; //舊的map的size size_type __new_num_nodes = __old_num_nodes + __nodes_to_add; //新的map的size _Map_pointer __new_nstart; if (_M_map_size > 2 * __new_num_nodes) //map目前的size若是大於兩倍的新的size { __new_nstart = _M_map + (_M_map_size - __new_num_nodes) / 2 + (__add_at_front ? __nodes_to_add : 0); if (__new_nstart < _M_start._M_node) copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart); else copy_backward(_M_start._M_node, _M_finish._M_node + 1, __new_nstart + __old_num_nodes); } else { size_type __new_map_size = _M_map_size + max(_M_map_size, __nodes_to_add) + 2; //配置一塊空間,給map用 _Map_pointer __new_map = _M_allocate_map(__new_map_size); __new_nstart = __new_map + (__new_map_size - __new_num_nodes) / 2 + (__add_at_front ? __nodes_to_add : 0); copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart); _M_deallocate_map(_M_map, _M_map_size); //設定新map起始地點大小 _M_map = __new_map; _M_map_size = __new_map_size; }
//從新設置開始迭代器和結束迭代器 _M_start._M_set_node(__new_nstart); _M_finish._M_set_node(__new_nstart + __old_num_nodes - 1); }