一篇文章搞懂STL中的顺序容器之Vector

 

Table of Contents

 

0.概述

1.迭代器(成员变量)

2.数据结构(成员变量)

3.内存管理(成员函数)

内存扩容

构造函数

push_back()函数 

pop_back函数

insert函数

erase函数

clear函数

析构函数

4.使用方法

5.相关问题

6.参考


0.概述

vector动态数组, 顾名思义 ,空间可以动态变化的数组,自然与数组array非常相似.
array使用时必须一开始就定好使用空间,定好以后就不能变了,
使用途中要想让空间大一点,必须在重新开辟一块更大的内存空间,然后把原来内存空间的数据都搬运过去.
vector就不一样了,在元素加入的过程中会自动扩充空间,这样就更灵活,没有必要害怕因为内存不足就一开始开辟一个特别大的空间
那么vector是怎么实现这一特性的呢?废话不多说 直接上源码

// alloc 是SGI STL的空间配置器
template<class T,class Alloc=alloc>
class vector{
   public:
     //vector的嵌套型别定义
     typedef  T             value_type;
     typedef  value_type*   pointer;
     typedef  value_type*   iterator;
     typedef  value_type*   reference;
     typedef  size_t        size_type;
     typedef  ptrdiff_t     difference_type; 
   protected:
     //simple_alloc 是SGI STL的空间配置器
     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=finsih;
     }

  public:
     iterator begin(){return start;}
     iterator end(){return finish;}
     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 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(){
         destroy(start,finish);
         deallocate();
     }

     reference front(){return *begin();}//第一个元素
     reference back() {return *(end()-1);}//最后一个元素
     void push_back(const T& x){//将元素插入至最尾端
         if(finish!=end_of_storage){
             construct(finish,x);
             ++finish;
         }
         else
            insert_aux(end(),x);
     }

     void pop_back(){//将最尾端元素取出
         --finish;
         destroy(finish);//全局函数
     }

     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());
         else
             insert(end(),new_size-size(),x);
     }
     void resize(size_type new_size){resize(new_size,T());}
     void clear() {erase(begin(),end());}

 protected:
     //配置空间并填满内容
     iterator allocate_and_fill(size_type n,const T& x)
     {
         iterator result=data_allocator::allocate(n);
         uninitialized_fill_n(result,n,x);
         return result;
     }
};


下面将源码分为几个点依次讲解

1.迭代器(成员变量)

vector维护的是一个连续的线性空间,
由于是连续线性空间,
所以其迭代器所要进行的一些操作比如:*,->,+,-,++,--等等普通的指针都可以满足
所以vector的迭代器就是普通指针.
通过普通指针也可让vector随机存取(所以vector的迭代器是Random Access Iterator)
看一下vector源码中,它的迭代器是怎么定义的

emplate<class T,class Alloc=alloc>
class vector{
   public:
       typedef     T             value_type;
       typedef     value_type*   iterator;//vector的迭代器是普通指针
};

因此,如果客户端写出这样的代码:

vector<int>::iterator ivite;
vector<Shape>::iterator svite;
ivite的型别就是int*,svitede 的型别就是Shape*

2.数据结构(成员变量)

在将vector的数据结构之前,先说一下vector的存储方式,
vector在使用时正常来说会有一部分正在使用的空间和一部分备用空间,总的空间大小就叫做容量
容量永远大于等于其大使用空间大小,如果相等就是满载了
增加新元素时,如果元素超过了原来的容量,则下次再有新元素时整个vector就得另觅居所了
在另外一个居所上,容量将扩充至原来的两倍,如果还不够,则继续扩充
这个过程会经历"重新开辟新内存->搬运元素->释放原来的内存"
vector实现的关键在于它在内部定义了三个迭代器(指针),
一个start指向正在使用空间的头,一个fininsh指向正在使用空间的尾,一个end_of_storage表示目前可用空间的尾,
源码如下

template<class T,class Alloc=alloc>
class vector{
...
protected:
    iterator start;
    iterator finish;
    iterator end_of_storage;
};

演示如下图

通过这三个迭代器,就可以实现我们想要的很多操作,比如提供首尾标示,大小,容量,空容器判断,[ ]运算符,最前端元素,最后端元素等
 

template <class T,class Alloc=alloc>
class vector{
...
public:
    iterator begin(){return start;}
    iterator end(){return finish;}
    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);}
    reference front(){return *begin();}
    reference back() {return *(end()-1);}
...
};

 

3.内存管理(成员函数)

先用例子说明一下vector的内存扩容机制
下面将结合它的构造函数说明它是怎么开辟内存的
结合它的主要成员函数(push_back,pop_back,insert.erase,clear)是怎么操作内存的
结合它的析构函数说明它是怎么释放内存的

 

  • 内存扩容

扩容原理概述
新增元素:Vector通过一个连续的数组存放元素,
如果集合已满,在新增数据的时候,就要分配一块更大的内存,
将原来的数据复制过来,释放之前的内存,在插入新增的元素;
对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了 ;
初始时刻vector的capacity为0,塞入第一个元素后capacity增加为1;
不同的编译器实现的扩容方式不一样,VS2015中以1.5倍扩容,GCC以2倍扩容。
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
vector是C++标准库的一个动态数组容器,提供了一种方便的方式来存储和操作一系列的元素。vector可以自动调整大小,可以在尾部快速插入和删除元素,并且支持随机访问。 以下是vector的一些重要特点和用法: 1. 定义和初始化vector: 可以使用以下方式定义和初始化一个vector: ```cpp std::vector<int> vec; // 定义一个空的vector std::vector<int> vec1(5); // 定义一个包含5个默认初始化元素的vector std::vector<int> vec2(5, 10); // 定义一个包含5个值为10的元素的vector std::vector<int> vec3 = {1, 2, 3, 4, 5}; // 使用初始化列表初始化vector ``` 2. 访问和修改元素: 可以使用下标运算符[]或at()函数来访问和修改vector的元素。例如: ```cpp std::vector<int> vec = {1, 2, 3, 4, 5}; int firstElement = vec; // 访问第一个元素 int secondElement = vec.at(1); // 访问第二个元素 vec = 10; // 修改第三个元素的值为10 ``` 3. 插入和删除元素: 可以使用push_back()函数在vector的尾部插入一个元素,使用pop_back()函数删除尾部的元素。也可以使用insert()函数在指定位置插入元素,使用erase()函数删除指定位置的元素。例如: ```cpp std::vector<int> vec = {1, 2, 3}; vec.push_back(4); // 在尾部插入元素4 vec.pop_back(); // 删除尾部的元素 vec.insert(vec.begin() + 1, 10); // 在第二个位置插入元素10 vec.erase(vec.begin() + 2); // 删除第三个位置的元素 ``` 4. 获取vector的大小和容量: 可以使用size()函数获取vector元素的个数,使用capacity()函数获取vector的容量(即当前分配的内存空间大小)。例如: ```cpp std::vector<int> vec = {1, 2, 3, 4, 5}; int size = vec.size(); // 获取元素个数,结果为5 int capacity = vec.capacity(); // 获取容量,结果可能大于等于5 ``` 5. 遍历vector: 可以使用迭代器或范围for循环来遍历vector的元素。例如: ```cpp std::vector<int> vec = {1, 2, 3, 4, 5}; for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } // 或者使用范围for循环 for (int num : vec) { std::cout << num << " "; } ``` 这些只是vector的一些基本用法,还有很多其他的函数和特性可以探索和使用。你可以参考C++标准库的文档或其他相关资料来深入了解vector的更多用法和细节。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值