我们已经学习了deque
的数据结构和它的迭代器,接下来我们继续学习它的构造及内存申请等内容。
deque
的构造函数/* 指针数组不申请空间
* 并且first和finish迭代器也调用默认构造函数
*/
public:
deque()
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(0);
}
/* 分配了空间之后
* 将x中的元素拷贝过去
*/
deque(const deque& x)
: start(), finish(), map(0), map_size(0)
{
//申请指针数组map的大小及线性空间(缓冲区buffer)
create_map_and_nodes(x.size());
__STL_TRY {
uninitialized_copy(x.begin(), x.end(), start);
}
__STL_UNWIND(destroy_map_and_nodes());
}
fill_initialize
函数 deque(size_type n, const value_type& value)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value);
}
deque(int n, const value_type& value)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value);
}
deque(long n, const value_type& value)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value);
}
explicit
关键字已经见到过几次了,用途是防止隐式转换 explicit deque(size_type n)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value_type());
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
deque(InputIterator first, InputIterator last)
: start(), finish(), map(0), map_size(0)
{
//range_initialize根据迭代器的类型选择最优的初始化方式
range_initialize(first, last, iterator_category(first));
}
#else /* __STL_MEMBER_TEMPLATES */
deque(const value_type* first, const value_type* last)
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(last - first);
__STL_TRY {
uninitialized_copy(first, last, start);
}
__STL_UNWIND(destroy_map_and_nodes());
}
deque(const_iterator first, const_iterator last)
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(last - first);
__STL_TRY {
uninitialized_copy(first, last, start);
}
__STL_UNWIND(destroy_map_and_nodes());
}
#endif /* __STL_MEMBER_TEMPLATES */
create_map_and_nodes
申请指针数组map的大小及线性空间(缓冲区buffer)
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::create_map_and_nodes(size_type num_elements) {
/* 计算结点个数
* buffer_size()返回每段线性空间能容量元素的个数
* num_elements代表需要申请的元素的个数
* num_nodes代表需要申请的结点个数
*/
size_type num_nodes = num_elements / buffer_size() + 1;
/* map至少有8个结点,最多num_nodes + 2
* 之所以要设计成num_nodes + 2
* 是为了当插入元素分别到尾部和首部时有一定的扩展性,而不用一插入元素就分配空间
*/
map_size = max(initial_map_size(), num_nodes + 2);
//申请空间
map = map_allocator::allocate(map_size);
map_pointer nstart = map + (map_size - num_nodes) / 2;
map_pointer nfinish = nstart + num_nodes - 1;
map_pointer cur;
__STL_TRY {
/* 申请一整段线性空间
* allocate_node的原型如下
* return data_allocator::allocate(buffer_size();
*/
for (cur = nstart; cur <= nfinish; ++cur)
*cur = allocate_node();
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
//处理异常情况
for (map_pointer n = nstart; n < cur; ++n)
deallocate_node(*n);
map_allocator::deallocate(map, map_size);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
//维护start和finish迭代器
start.set_node(nstart);
finish.set_node(nfinish);
start.cur = start.first;
finish.cur = finish.first + num_elements % buffer_size();
}
deque
的初始化操作fill_initialize
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::fill_initialize(size_type n,
const value_type& value) {
//创建map和nodes
create_map_and_nodes(n);
map_pointer cur;
__STL_TRY {
//初始化每一个node节点
//初始化未初始化的值为value
for (cur = start.node; cur < finish.node; ++cur)
uninitialized_fill(*cur, *cur + buffer_size(), value);
//随最后一个节点特殊处理,因为最后一个节点不一定会被填满
uninitialized_fill(finish.first, finish.cur, value);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
//处理异常情况,将所有节点销毁
for (map_pointer n = start.node; n < cur; ++n)
destroy(*n, *n + buffer_size());
destroy_map_and_nodes();
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
}
range_initialize
在进行构造的时候传入的迭代器也有可能是别的类型的迭代器,不一定是random_access_iterator
以下range_initialize
根据不同的情况写了不同的重载版本
template <class T, class Alloc, size_t BufSize>
template <class InputIterator>
void deque<T, Alloc, BufSize>::range_initialize(InputIterator first,
InputIterator last,
input_iterator_tag) {
create_map_and_nodes(0);
for ( ; first != last; ++first)
//一个节点一个节点地插入
push_back(*first);
}
template <class T, class Alloc, size_t BufSize>
template <class ForwardIterator>
void deque<T, Alloc, BufSize>::range_initialize(ForwardIterator first,
ForwardIterator last,
forward_iterator_tag) {
size_type n = 0;
//计算出[first, last)范围内的节点个数
distance(first, last, n);
//申请空间
create_map_and_nodes(n);
__STL_TRY {
//拷贝
uninitialized_copy(first, last, start);
}
//失败则直接销毁
__STL_UNWIND(destroy_map_and_nodes());
}
deque
的析构和内存释放 ~deque() {
destroy(start, finish);
destroy_map_and_nodes();
}
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::destroy_map_and_nodes() {
for (map_pointer cur = start.node; cur <= finish.node; ++cur)
deallocate_node(*cur);
//释放空间
map_allocator::deallocate(map, map_size);
}
我们学习了deque
的构造,析构等。
我们可以看出deque
为了维护它独特的数据结构付出了很多代价,很多的操作都变得异常艰难和复杂,但是只要理解到它的数据结构这些都不难理解。接下来我们将继续学习deque
的一些相关操作,要看懂这些代码的前提是我们必须深刻地理解deque
的数据结构。