1、vector概述
vector与array非常相似,两者唯一差别在于空间的运用的灵活性。array是静态空间,一旦配置了就不能改变;vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。vector的实现技术关键在于其对大小的控制以及重新配置时的数据移动效率,一旦vector旧空间满载扩充空间将会是“配置新空间/数据移动/释放旧空间”的大工程。
2、vector迭代器
vector的迭代器型别是Random Access Iterators随机存取,而普通指针正有着这样的能力,所以vector的迭代器就是普通指针,支持的操作有operator*,operator->,operator++,operator--,operator+,operator-,operator+=,operator-=。
typedef value_type* iterator;
3、vector数据结构
vector所采用的数据结构非常简单:线性连续空间。它以两个迭代器start和finish分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器end_of_storage指向连续空间(含备用空间)的尾端。
template <class T, class Alloc = alloc>
class vector {
public:
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<value_type, Alloc> data_allocator;
iterator start;
iterator finish;
iterator end_of_storage;
void insert_aux(iterator position, const T& x);
void deallocate() {
if (start) data_allocator::deallocate(start, end_of_storage - start);
}
void fill_initialize(size_type n, const T& value) {
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
}
public:
iterator begin() { return start; }
const_iterator begin() const { return start; }
iterator end() { return finish; }
const_iterator end() const { return finish; }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
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()); }
bool empty() const { return begin() == end(); }
reference operator[](size_type n) { return *(begin() + n); }
const_reference operator[](size_type n) const { return *(begin() + n); }
vector() : start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const T& value) { fill_initialize(n, value); }
vector(int n, const T& value) { fill_initialize(n, value); }
vector(long n, const T& value) { fill_initialize(n, value); }
explicit vector(size_type n) { fill_initialize(n, T()); }
vector(const vector<T, Alloc>& x) {
start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
finish = start + (x.end() - x.begin());
end_of_storage = finish;
}
}
4、vector构造与内存管理
当使用push_back将新元素插入于vector尾端时,该函数首先检查是否还有备用空间,如果有直接在备用空间上构造元素,并调整迭代器finish,使vector变大;否则先扩充空间重新配置、移动数据、释放旧空间。注意:对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。
insert_aux(iterator position, const T& x)函数是在position位置上插入元素x,它会先检查vector是否还有备用空间,如果有在备用空间起始处构造一个元素,并以vector最后一个元素值为其初值,然后再将[position,finish-1)范围的值copy_backward到终止位置为finish处,这样相当于将position处位置空出来了,其后面的元素全部往后复制一格,最后将x复制给*position且++finish;如果没有备用空间,先申请新vector的空间,配置原则为大小的两倍(原大小不为0,否则为1),然后将原vector[start,position)范围内容拷贝到新vector,在新vector构造新元素x,将原vector剩下的[position,finish)范围内容拷贝到新vector并更新start、finish、end_of_storage。
void push_back(const T& x) {
if (finish != end_of_storage) {
construct(finish, x);
++finish;
}
else
insert_aux(end(), x);
}
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
if (finish != end_of_storage) {
construct(finish, *(finish - 1));
++finish;
T x_copy = x;
copy_backward(position, finish - 2, finish - 1);
*position = x_copy;
}
else {
const size_type old_size = size();
const size_type len = old_size != 0 ? 2 * old_size : 1;
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start);
construct(new_finish, x);
++new_finish;
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(begin(), end());
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
5、vector元素操作
(1)pop_back
将尾端元素拿掉,并调整大小
void pop_back() {
--finish;
destroy(finish);
}
(2)erase
erase有两个重载函数,一个是清除掉某个位置上的元素,另一个是清除[first,last)范围中的元素,无论是哪种都得先将清除范围之后[last,finish)的元素copy到清除范围起始位置first处,然后再析构finish - (last - first)之后的所有元素并释放空间。
iterator erase(iterator position) {
if (position + 1 != end())
copy(position + 1, finish, position);
--finish;
destroy(finish);
return position;
}
iterator erase(iterator first, iterator last) {
iterator i = copy(last, finish, first);
destroy(i, finish);
finish = finish - (last - first);
return first;
}
(3)clear
erase掉vector中所有元素
void clear() { erase(begin(), end()); }
(4)insert
在position位置上插入n个元素值为x,插入的过程中总会伴随着新对象的构造,vector的思想是尽量减少对象的构造次数,所以总构造对象数是n,接在原有对象的后面,这样只要知道最后这n位的元素值是多少,接在finish后面构造n个对象值就可以了,因为n的大小会影响构造的对象值所以分为两种情况。
①当备用空间大于等于新增元素个数
如果插入点之后的现有元素元素个数大于新增元素个数:那么finish后的[finish,n+finish)之间n个元素值为原来[finish-n,finish)的值,再之后[position,finsh-n)的值复制到[position+n,finish),最后[position,position+n)全部填充为x就是插入的值。
如果插入点之后的现有元素元素个数小于等于新增元素个数:那么finish后的[finish,n+position)之间n-(finish-position)个元素值为x,再之后[position+n,finsh+n)是原来[position,finish)的值,而[position,finish)的值全部填充为x。
最后更新finish。
②当备用空间小于新增元素个数
必须配置额外的内存空间,配置的空间大小为旧长度的两倍或者旧长度+新增大小,先将旧vector的插入点之前[start,position)的元素复制到新空间,再将新增元素填入新空间,最后将旧vector插入点之后[position,finish)的元素复制到新空间,并释放旧vector更新start、finish、end_of_storage。
template <class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, size_type n, const T& x) {
if (n != 0) {
if (size_type(end_of_storage - finish) >= n) {
T x_copy = x;
const size_type elems_after = finish - position;
iterator old_finish = finish;
if (elems_after > n) {
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish);
fill(position, position + n, x_copy);
}
else {
uninitialized_fill_n(finish, n - elems_after, x_copy);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
fill(position, old_finish, x_copy);
}
}
else {
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start);
new_finish = uninitialized_fill_n(new_finish, n, x);
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(start, finish);
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}