目录
vector容器基本能够支持任何类型的对象,存放在连续空间,同时是一个可以动态增长的数组
本节中我们主要分析了关于vector
满足traits
编程规范的定义, 构造函数, 析构函数, 数组的基本信息获取函数
traits编程规则要求每个使用traits萃取器的都必须自己定义五个嵌套型别
vector要求连续空间的大小要比用户自己要求的空间大两倍(留着备用,实现动态增长),因此vector也有个弊端就是备用空间也用完后,需要申请更大的空间,然后释放之前的空间。(不过为了动态增长,选择接受..)
- template <class T, class Alloc = alloc>
- class vector
- {
- public:
- // 定义vector自身的嵌套型别
- typedef T value_type;
- typedef value_type* pointer;
- typedef const value_type* const_pointer;
- // 定义迭代器, 这里就只是一个普通的指针
- typedef value_type* iterator;
- typedef const value_type* const_iterator;
- typedef value_type& reference;
- typedef const value_type& const_reference;
- typedef size_t size_type;
- typedef ptrdiff_t difference_type;
- ...
- protected:
- typedef simple_alloc
data_allocator; // 设置其空间配置器 - iterator start; // 使用空间的头
- iterator finish; // 使用空间的尾
- iterator end_of_storage; // 可用空间的尾
- ...
- };
可以看出,用start来指向一片内存的开头,finish=start+n,一开始e_o_s就是finish
- vector() : start(0), finish(0), end_of_storage(0) {} // 默认构造函数
- explicit vector(size_type n) { fill_initialize(n, T()); } // 必须显示的调用这个构造函数, 接受一个值
- vector(size_type n, const T& value) { fill_initialize(n, value); } // 接受一个大小和初始化值. int和long都执行相同的函数初始化
- vector(int n, const T& value) { fill_initialize(n, value); }
- vector(long n, const T& value) { fill_initialize(n, value); }
- vector(const vector
& x); // 接受一个vector参数的构造函数
- // 初始化vector的使用空间头和空间的尾
- void fill_initialize(size_type n, const T& value)
- {
- start = allocate_and_fill(n, value); // 初始化并初始化值
- finish = start + n;
- end_of_storage = finish;
- }
- // 调用默认的第二配置器分配内存, 分配失败就释放所分配的内存
- iterator allocate_and_fill(size_type n, const T& x)
- {
- iterator result = data_allocator::allocate(n); // 申请n个元素的线性空间.
- __STL_TRY // 对整个线性空间进行初始化, 如果有一个失败则删除全部空间并抛出异常.
- {
- uninitialized_fill_n(result, n, x);
- return result;
- }
- __STL_UNWIND(data_allocator::deallocate(result, n));
- }
vector
有一个接受vector参数的构造函数, 调用的是uninitialized_copy
执行初始化, 我们在上一篇分析过该函数
- vector(const vector
& x) - {
- start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
- finish = start + (x.end() - x.begin()); // 初始化头和尾迭代器位置
- end_of_storage = finish;
- }
- // 同样进行初始化
- template <class ForwardIterator>
- iterator allocate_and_copy(size_type n, ForwardIterator first, ForwardIterator last)
- {
- iterator result = data_allocator::allocate(n);
- __STL_TRY
- {
- uninitialized_copy(first, last, result); // 这里采用的是uninitialized_copy, 进行复制.
- return result;
- }
- __STL_UNWIND(data_allocator::deallocate(result, n));
- }
-
- #else /* __STL_MEMBER_TEMPLATES */
- // 支持两个迭代器表示范围的复制
- iterator allocate_and_copy(size_type n,
- const_iterator first, const_iterator last)
- {
- iterator result = data_allocator::allocate(n);
- __STL_TRY {
- uninitialized_copy(first, last, result);
- return result;
- }
- __STL_UNWIND(data_allocator::deallocate(result, n));
- }
- #endif /* __STL_MEMBER_TEMPLATES */
- };
接受两个迭代器, 构造一个范围的数据
- #ifdef __STL_MEMBER_TEMPLATES
- template <class InputIterator>
- vector(InputIterator first, InputIterator last) :
- start(0), finish(0), end_of_storage(0)
- {
- range_initialize(first, last, iterator_category(first));
- }
- #else /* __STL_MEMBER_TEMPLATES */
- vector(const_iterator first, const_iterator last) {
- size_type n = 0;
- distance(first, last, n);
- start = allocate_and_copy(n, first, last);
- finish = start + n;
- end_of_storage = finish;
- }
- #endif /* __STL_MEMBER_TEMPLATES */
析构函数就是直接调用deallocate
空间配置器, 从头释放到数据尾部, 最后将内存还给空间配置器.
vector
因为是类, 所以我们并不需要手动的释放内存, 生命周期结束后就自动调用析构从而释放调用空间, 当然我们也可以直接调用析构函数释放内存
- void deallocate()
- {
- if (start)
- data_allocator::deallocate(start, end_of_storage - start);
- }
- // 调用析构函数并释放内存
- ~vector()
- {
- destroy(start, finish);
- deallocate();
- }
- public:
- // 获取数据的开始以及结束位置的指针. 记住这里返回的是迭代器, 也就是vector迭代器就是该类型的指针.
- iterator begin() { return start; }
- iterator end() { return finish; }
- // 获取值
- reference front() { return *begin(); }
- reference back() { return *(end() - 1); }
- // 获取右值
- const_iterator begin() const { return start; }
- const_iterator end() const { return finish; }
- const_reference front() const { return *begin(); }
- const_reference back() const { return *(end() - 1); }
- // 获取基本数组信息
- size_type size() const { return size_type(end() - begin()); } // 数组元素的个数
- size_type max_size() const { return size_type(-1) / sizeof(T); } // 最大能存储的元素个数
- size_type capacity() const { return size_type(end_of_storage - begin()); } // 数组的实际大小
判断vector是否为空, 并不是比较元素为0, 是直接比较头尾指针
bool empty() const { return begin() == end(); }
vector的迭代器是一个普通的指针
构造函数的重载满足不同的用户需求
vector因为是类, 所以在生命周期结束后会自动调用析构函数, 用户不再手动的释放内存, 也不会出现内存泄露的问题, 用户也可以主动调用析构函数释放内存
finish是指向最后一个元素的后一位地址, 不是直接指向最后一个元素