deque

deque文档

deque,她的意思为双端队列(double-ended queue)。逻辑上看,deque和vector都是连续空间。相比于vector只能从尾部增长元素,而deque可在双侧增加元素。但是从存储结构上,deque并非是连续空间存储的。它是分段连续的。对于vector存储(申请的内存)的增长,可以描述为三个步骤1.申请内存2.搬移元素3释放原先的使用的内存。而由于deque其特殊的数据结构,如下图所示,省去这三个步骤。(但是仍然需要申请buffer去存储新元素,不用去搬移旧有元素了)。

deque的组成(数据成员):

iterator start;
iterator finish;
map_pointer map;
size_type mapsize;//map大小

由于其特殊的数据结构,其迭代器的设计也会较为繁琐。因为是分段连续的。尤其是跨过分段是的特殊处理需要尤其注意。对于下图的说明:map存储着各个buffer(存储数据的数据段)的指针。迭代器(start,finish)则存储着该元素所在buffer的首尾,以及,目前所在位置(cur),还有其所在buffer在map上的信息。因此迭代器的设计较与vector的设计还是非常复杂的。

deque

 

 

deque的构造与析构

构造函数:与vector,string之前的构造函数类似

构造函数类型 具体函数
default (1) deque(); explicit deque (const allocator_type& alloc);
fill (2) explicit deque (size_type n, const allocator_type& alloc = allocator_type()); deque (size_type n, const value_type& val, const allocator_type& alloc = allocator_type());
range (3) template < class InputIterato r> deque (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());
copy (4) deque (const deque& x); deque (const deque& x, const allocator_type& alloc);
move (5) deque (deque&& x); deque (deque&& x, const allocator_type& alloc);
initializerlist(6) deque (initializer_list il, const allocator_type& alloc = allocator_type());

 

= 赋值

赋值函数类型 等号重载
copy (1) deque& operator= (const deque& x); //拷贝赋值函数
move (2) deque& operator= (deque&& x); //移动赋值函数
initializer list (3) deque& operator= (initializer_list il);//利用初始化列表进行赋值

assign

赋值函数类型 重载
range (1) template void assign (InputIterator first, InputIterator last);
fill (2) void assign (size_type n, const value_type& val) ;
initializer list (3) void assign (initializer_list il);

 

deque元素访问

迭代器(类指针访问方式)

值得注意的是:虽然deque的内存表现不是连续的(分段连续),但是通过存储的数据,通过对一些符号的重载,仍能使得我们像连续空间那样去使用迭代器。迭代器只不过是定义了一堆行为像指针的类而已。对于下面的各个函数,其中以“c"开头的函数(如cbegin()、cend()),返回的是const iterator类型(类似于指向常量的指针),而"r"与”cr“开头表示(const and reverse),反向迭代器以及常量反向迭代器。

Iterators  
begin cbegin returns an iterator to the beginning (public member function)
end cend returns an iterator to the end (public member function)
rbegin crbegin returns a reverse iterator to the beginning (public member function)
rend crend returns a reverse iterator to the end (public member function)

元素访问

Element access 函数原型及其说明
at access specified element with bounds checking (public member function),带有边界检查的访问特定元素访问方式 reference at( size_type pos ); const_reference at( size_type pos ) const;
operator[] access specified element (public member function) reference operator[ ] ( size_type pos ); const_reference operator[ ] ( size_type pos ) const;
front access the first element (public member function) reference front(); const_reference front() const;
back access the last element (public member function) reference back(); const_reference back() const;

容量与大小

不同与vector,string有capacity函数可以查看已经申请的空间。而deque不行。实际通过了解其的数据成员可以知道,不像vector有end_of_storage这样的迭代器,并且也可以知道他也

Capacity 函数原型及说明
empty checks whether the container is empty (public member function),判断容器是否为空 bool empty() const;
size returns the number of elements (public member function) size_type size() const;
max_size returns the maximum possible number of elements (public member function),返回可能的最大元素个数 size_type max_size() const;
shrink_to_fit(C++11) reduces memory usage by freeing unused memory (public member function),可以释放内存 void shrink_to_fit();

容器修改

对于clear函数。对于vector不会释放其内存空间。而clear会。(这点可以通过申请一个比较大的内存的deque,然后观察程序的占用内存变化,可以清楚看到deque的clear是会释放内存的)。对于使用clear后的所占有的内存大小。可以参考,《STL源码分析》中的一段话:deque的最初状态(无任何元素时)保有一个缓冲区,因此,clear()完成之后回复初始状态,也一样要保留一个缓冲区。

对于emplace,这个函数是想要通过传入的参数以及所申请的空间,直接在指定位置构造新元素。由于内存结构仍然是线性的,所以在中间部分emplace的效率仍然是很低的,不如list以及foward_list。

对于swap。在vector有这样的小技巧(可以使一个vector对象与一个右值swap,可以达到释放空间的目的)

vector<int> v1{1,2,3};
v1.swap((vector<int>){1});//对于vector可行,对于deque不可行,因为没有传入右值参数的函数原型
​

 

Modifiers 函数原型及说明
clear clears the contents (public member function),清除内容,所有迭代器失效。deque的clear会清除部分申请的内存空间! void clear();
insert inserts elements (public member function)依据传入参数分类 single element (1) 单元素 iterator insert (iterator position, const value_type& val); fill (2) 填充 void insert (iterator position, size_type n, const value_type& val); range (3) 通过迭代器的范围插入(要求值类型一致) template < class InputIterator > void insert (iterator position, InputIterator first, InputIterator last);
emplace(C++11) constructs element in-place (public member function)在指定位置构造元素 template <class... Args> iterator emplace (const_iterator position, Args&&... args);
erase erases elements (public member function) iterator erase (const_iterator position ); iterator erase (const_iterator first, const_iterator last );
push_back adds an element to the end (public member function) void push_back (const value_type& val); void push_back (value_type&& val);
emplace_backC++11) constructs an element in-place at the end (public member function) template <class... Args> void emplace_back (Args&&... args);
pop_back removes the last element (public member function) void pop_front();
push_front inserts an element to the beginning (public member function) void push_front (const value_type& val); void push_front (value_type&& val);
emplace_frontC++11) constructs an element in-place at the beginning (public member function) template <class... Args> void emplace_front (Args&&... args);
pop_front removes the first element (public member function) void pop_front();
resize changes the number of elements stored (public member function) void resize (size_type n); void resize (size_type n, const value_type& val);
swap swaps the contents (public member function) void swap (deque& x);

 

 

Reference

[1]《STL源码剖析》候捷

[2]C++ STL 体系结构与内核分析--从平地到万丈高楼-----候捷视频课程,https://www.bilibili.com/video/av45108908

[3]http://www.cplusplus.com/reference/deque/deque/

[4]https://en.cppreference.com/w/cpp/container/deque