提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
vector的定义
vector可以理解为一个动态数组,他能够自适应地变更自己的大小。总之就是很厉害。
看看SGI vector的相关定义代码
template <class T, class Alloc = alloc>
class vector{
public:
//通过模板推断
typedef T value_type;
typedef T* pointer;
typedef T* iterator;
typedef T& 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 != nullptr){
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()const {return start;}
iterator end() {return finish;}
//size_type()这种是新时代的c++的强转,应该更潮更in
size_type size() const {return size_type(end() - begin());}
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);
}
vector(): start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const value_type& value){
fill_initialize(n, value);
}
vector(int n, const value_type& value){
fill_initialize(n, value);
}
vector(long n, const value_type& value){
fill_initialize(n, value);
}
explicit vector(size_type n){
fill_initialize(n, value_type());
}
~vector(){
destroy(start, finish);
deallocate();
}
reference front() {return *begin();}
reference back() {return *(end() - 1);}
void push_back(const T& x){
if(end() != end_of_storage){
construct(end(), x);
++finish;
}else{
insert_aux(end(), x);
}
}
void pop_back(){
if(end() != begin()){
--finish;
destroy(end())
}
}
iterator erase(iterator position){
if(position + 1 != end()){
copy(position + 1, finish, position);
}
--finish;
destroy(finish);
return position;
}
void resize(size_type new_size, const T& x){
if(new_size < size()){
erase(begin() + new_size, end());
finish = new_size;
}else{
insert(end(), new_size - size(), x);
}
}
void resize(size_type new_size) {resize(new_sizse, T());}
void clear(){erase(begin(), end());}
protected:
iterator allocate_and_fill(size_type n, const value_type& value){
iterator result = data_allocator::allocate(n);
uninitialized_fill_n(result, n, x);
return result;
}
上面可以看出vector的功能,他能存储东西,push_back实现了存储,他能动态分配存储大小,于是他实现了allocate和deallocate来进行内存管理,同时他还有一些更细节的功能如resize,但是总体看下来是很友好易理解的。
提示:以下是本篇文章正文内容,下面案例可供参考
vector的空间分配算法
从使用者的角度,我们所需要的容器不应该是一个静态大小的,他应该是能在存储小数据量数据时不开太大的内存空间,又有存储大量数据量的能力,于是vector的空间扩充算法十分重要。
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));
T x_copy = x;
//不知道为什么这么写啊啊啊啊,为什么不直接用copy呢
//懂了,copy会有覆盖发生(在本例子中),而将最后一个元素先构造出来,在逆序赋值不会发生覆盖
//可以自己写个小例子测试一下
copy_backward(position, finish - 2, finish - 1);
*position = x_copy;
++finish;
}else{
const size_type old_size = size();
const size_type new_size = old_size == 0 ? 1 : 2 * old_size;
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
try{
new_finish = uninitialized_copy(start, position, new_start);
construct(new_finish, x);
++new_finish;
//注意这里算法的细节,以及如何保证线程安全
new_finish = uninitialized_copy(position, finish, new_finish);
}
catch(...)(
//destroy管理的是析构
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw
}
}
destroy(begin(), end());
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
空间扩展算法也很简单,就是遇到不够的时候扩大两倍。扩大的时候是新建空间而不是在原空间上新增。算法细节要注意元素位置以相关回滚的操作