STL源码剖析(vector)

在SGI STL中,vector使用的是连续的内存空间,迭代器使用普通指针来实现。

因为使用的是连续的内存空间,在vector容量不足的时候会直接分配一块新的内存,把原来的元素copy进去,回收原来的内存空间。

因此在vector扩容的时候,原来的所有迭代器都会失效。

vector的实现基本都是围绕这start、end、end_of_storage三个指针,首先先看看vector的基本定义

 1 template <class T, class Alloc = alloc>
 2 class vector {
 3 public:
 4     // 基本型别定义
 5     typedef T value_type;
 6     typedef value_type* pointer;
 7     typedef value_type* iterator;
 8     typedef value_type& reference;
 9     typedef size_t size_type;
10     typedef ptrdiff_t difference_type;
11 protected:
12     // 空间配置器 只是对Alloc的进一步封装
13     typedef simple_alloc<value_type, Alloc> data_allocator;
14     // 关键的几个迭代器
15     iterator start;
16     iterator finish;
17     iterator end_of_storage;
18 public:
19     vector() : start(0), finish(0), end_of_storage(0) {}
20     // 回收内存
21     void deallocate() {
22         if (start) data_allocator::deallocate(start, end_of_storage -    start);
23     }
24     ~vector() {
25         destroy(start, finish); // 对[start, finish)的元素调用相应的析构函数(如果是POD类型则什么都不做)
26         deallocate();
27     }
28     // 提供简单的接口
29     iterator begin() { return start; }
30     iterator end() { return finish; }
31     size_type size() const { return size_type(end() - begin()); }
32     size_type max_size() const { return size_type(-1) / sizeof(T); }
33     size_type capacity() const { return size_type(end_of_storage - begin()); }
34     bool empty() const { return begin() == end(); }
35     reference operator[](size_type n) { return *(begin() + n); }
36 };

因为vector实现比较简单,所以就不一一的列出全部成员函数的实现了,主要还是关注其关于插入元素的实现。

先看看比较常用的push_back的实现。

1 void push_back(const T& x) {
2     if (finish != end_of_storage) {
3       construct(finish, x); // 调用placement new构造对象
4       ++finish;
5     }
6     else // 容量不足的情况
7       insert_aux(end(), x);
8   }

insert_aux用于在position中插入元素,该函数还可以处理容量不足的情况

 1 template <class T, class Alloc>
 2 void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
 3     // 有剩余空间
 4     if (finish != end_of_storage) {
 5         construct(finish, *(finish - 1));
 6         ++finish;
 7         T x_copy = x;
 8         copy_backward(position, finish - 2, finish - 1);
 9         *position = x_copy;
10     }
11     // 容量不足
12     else {
13         const size_type old_size = size();
14         // 分配原来的两倍大小
15         const size_type len = old_size != 0 ? 2 * old_size : 1;
16         // 重新分配空间
17         iterator new_start = data_allocator::allocate(len);
18         iterator new_finish = new_start;
19         try {
20             // 将原来的内容复制到新的vector
21             new_finish = uninitialized_copy(start, position, new_start);
22             construct(new_finish, x);
23             ++new_finish;
24             new_finish = uninitialized_copy(position, finish, new_finish);
25         }
26         catch(...) {
27             destroy(new_start, new_finish);
28             data_allocator::deallocate(new_start, len);
29             throw;
30         }
31         // 析构并释放原来的vector
32         destroy(begin(), end());
33         deallocate();
34         // 调整三个迭代器
35         start = new_start;
36         finish = new_finish;
37         end_of_storage = new_start + len;
38   }
39 }

普通的insert函数也是通过insert_aux实现的

 1 iterator insert(iterator position, const T& x) {
 2     size_type n = position - begin();
 3     if (finish != end_of_storage && position == end()) {
 4         construct(finish, x);
 5         ++finish;
 6     }
 7     else
 8         insert_aux(position, x);
 9     return begin() + n;
10 }

对应的erase函数实现更加的简单

 1 iterator erase(iterator position) {
 2     if (position + 1 != end())
 3         copy(position + 1, finish, position);
 4     --finish;
 5     destroy(finish);
 6     return position;
 7 }
 8
 9 iterator erase(iterator first, iterator last) {
10     iterator i = copy(last, finish, first);
11     destroy(i, finish);
12     finish = finish - (last - first);
13     return first;
14 }

时间: 2024-10-26 06:16:44

STL源码剖析(vector)的相关文章

STL源码剖析——vector的实现原理总结

 vector的数据安排以及操作方式,与array非常相似.两者的唯一区别在于空间的运用的灵活性.array是静态空间,一旦配置了就不能改变:要换个大(或小)一点的房子,可以,一切琐细都得由客户端自己来:首先配置一块新空间,然后将元素从旧址一一搬往新址,再把原来的空间释还给系统.vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素.因此,vector的运用对于内存的合理利用与运用的灵活性有很大的帮助,我们再也不必因为害怕空间不足而一开始要求一个大块头的array了,

C++ 《STL源码剖析》学习-vector

本文章是笔者学习<STL源码剖析>的学习笔记,记录的是笔者的个人理解,因为个人的水平有限,难免会有理解不当的地方,而且该书出版的时间比较久,难免会有些不一样.如有不当,欢迎指出. vector是c++中经常用到的数据结构,而且在面试时也会有提及,因此了解vector很重要. 一说到vector,我们就很容易想到另外一个与它十分相似的数据结构,关于它们之间显著的差别,我觉得是在于空间运用的灵活性上.数组是静态的,在声明的时候就要指明其具体的空间大小,而vector是动态的,随着元素的增加,它内部

STL源码剖析 — 空间配置器(allocator)

前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配置器,配置的对象,是内存.(以下内容来自<STL源码剖析>) 空间配置器的标准接口 根据STL的规范,allocator的必要接口 各种typedef 1 allocator::value_type 2 allocator::pointer 3 allocator::const_pointer 4

STL&quot;源码&quot;剖析-重点知识总结

STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合套用: 容器(Containers):各种数据结构,如:vector.list.deque.set.map.用来存放数据.从实现的角度来看,STL容器是一种class template. 算法(algorithms):各种常用算法,如:sort.search.copy.erase.从实现的角度来看,STL算法

STL 源码剖析 算法 stl_algo.h -- random_shuffle

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie random_shuffle -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 描述:将[first

STL源码剖析 容器 stl_vector.h

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie vector ---------------------------------------------------------------------- 描述: 1.迭代器 vector 维护的是一个连续线性空间,它的迭代器是普通指针, 能满足 RandomAccessIterator 所有必要条件:operator*, operator->,operator++,operator--,

通读《STL源码剖析》之后的一点读书笔记

[QQ群: 189191838,对算法和C++感兴趣可以进来] 直接逼入正题. Standard Template Library简称STL.STL可分为容器(containers).迭代器(iterators).空间配置器(allocator).配接器(adaptors).算法(algorithms).仿函数(functors)六个部分. 迭代器和泛型编程的思想在这里几乎用到了极致.模板或者泛型编程其实就是算法实现时不指定具体类型,而由调用的时候指定类型,进行特化.在STL中,迭代器保证了ST

STL源码剖析 --- 空间配置器 std::alloc

STL是建立在泛化之上的.数组泛化为容器,参数化了所包含的对象的类型.函数泛化为算法,参数化了所用的迭代器的类型.指针泛化为迭代器,参数化了所指向的对象的类型.STL中的六大组件:容器.算法.迭代器.配置器.适配器.仿函数. 这六大组件中在容器中分为序列式容器和关联容器两类,正好作为STL源码剖析这本书的内容.迭代器是容器和算法之间的胶合剂,从实现的角度来看,迭代器是一种将operator*.operator->.operator++.operator-等指针相关操作予以重载的class tem

《STL源码剖析》---stl_hashtable.h阅读笔记

在前面介绍的RB-tree红黑树中,可以看出红黑树的插入.查找.删除的平均时间复杂度为O(nlogn).但这是基于一个假设:输入数据具有随机性.而哈希表/散列表hash table在插入.删除.查找上具有"平均常数时间复杂度"O(1):且不依赖输入数据的随机性. hash table的实现有线性探测.二次探测.二次散列等实现,SGI的STL是采用开链法(separate chaining)来实现的.大概原理就是在hash table的每一项都是个指针(指向一个链表),叫做bucket.