STL_Vector

本文深入解析C++标准库中的模板类vector,详细阐述其成员类型定义、迭代器操作、内存管理(如扩容机制)以及插入、删除、赋值等核心操作。重点讨论了插入元素时如何判断是否需要扩容以及如何高效地迁移数据。同时,介绍了vector的构造函数、析构函数以及赋值运算符的实现。
摘要由CSDN通过智能技术生成
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:
// 三个基础位置下标,所有的数据操作都是通过这三个下标获取
  iterator start;     // 起始位置
  iterator finish;    // 结束位置
  iterator end_of_storage;    // 是否越界,越界需要扩容

  /*其他类的通用函数*/
  uninitialized_copy(start, position, new_start);   // 把start, position之间的数据拷贝到new_start中,返回拷贝后,最后一位有数据的元素的下标指针


// vector扩容函数(扩容时,整个都要复制到新的内存空间中,挪动一次位置)
// 参数:插入位置【迭代器位置】、插入值
/*内存空间够,从尾部插入,直接插入;内存空间够,从中间插入,开辟新的内存空间,然后把插入位置之前的元素插入新内存空间,再把新的元素和位置之后元素插入内存空间
内存空间不够,尾部插入,先扩容,再执行插入;内存空间不够,从中间插入,先扩容,再执行插入;*/
/*
I如果内存空间够,且从尾部插入。那么将元素插入尾部,且finish指针指向新插入的尾部元素{只有尾部插入,且内存空间够的情况下,不涉及内存的增加删除}。

II【A-新-B】如果内存空间够,且从中间插入。那么先开辟一块新内存空间,
<1>将插入元素位置之前的元素【A】拷贝到新的内存空间,返回最后一个元素的迭代器位置,
<2>把新插入元素,放置到插入位置之后的数据前面【新-B】,
<3>把【新-B】拷贝到【A】所在的内存空间之后,形成新的顺序表【A-新-B】,<4>修改下标,析构原始元素,释放原始元素的内存空间。{需要开辟新的内存空间,用完过后再删除}

III如果内存空间不够,且从尾部插入。
<1>获取当前容器长度,
<2>如果原大小为0,那么容器长度增加1,。如果原大小不为0,那么容器长度变成当前的2倍,
<3>申请新的容器长度的内存,
<4>把原数据拷贝到新的容器里面,
<5>再把新的数据也拷贝到新的容器中,
<6>修改下标,析构原始元素,释放原始元素的内存空间。{需要开辟新的内存空间,用完过后再删除}

IV如果内存空间不够,且从中间插入。
<1>获取当前容器长度,
<2>如果原大小为0,那么容器长度增加1,。如果原大小不为0,那么容器长度变成当前的2倍,
<3>申请新的容器长度的内存,
<4>将插入元素位置之前的元素【A】拷贝到新的内存空间,返回最后一个元素的迭代器位置,
<5>把新插入元素,放置到插入位置之后的数据前面【新-B】,
<6>把【新-B】拷贝到【A】所在的内存空间之后,形成新的顺序表【A-新-B】,
<7>修改下标,析构原始元素,释放原始元素的内存空间。{需要开辟新的内存空间,用完过后再删除}
*/
void 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);    // 把数据放到vector里,修改finish指针,并回退一个位置
    *position = x_copy;
  }
  // 如果越界了,没有备用空间,那么需要扩容
  else {
    const size_type old_size = size();  // 获取当前长度
    const size_type len = old_size != 0 ? 2 * old_size : 1;   // 如果原大小为0,那么增加1,如果原大小不为0,那么增加1倍长度,变成从前的2倍
    iterator new_start = data_allocator::allocate(len);     // 申请新的内存,申请内存的长度为原内存的2倍
    iterator new_finish = new_start;
    __STL_TRY {
      new_finish = uninitialized_copy(start, position, new_start);    // 将原数据【插入位置之前的数据】拷贝到new_start中,返回最后一个元素
      construct(new_finish, x);   // 把终止元素替换成新插入元素
      ++new_finish;   // 结束位置下标后移一位
      new_finish = uninitialized_copy(position, finish, new_finish);  // 把新数据【插入位置到结束的数据】拷贝到new_finish中,返回最后一个元素
    }
    destroy(begin(), end());    // 析构原始值
    deallocate();               // 释放原空间
    start = new_start;          // 重新调整三个指针
    finish = new_finish;
    end_of_storage = new_start + len;
  }
}

// 释放整个容器的内存空间。从起始位置开始,往后释放最大容量-开始位置长度的元素。
 void deallocate() {   
    if (start) data_allocator::deallocate(start, end_of_storage - start);
  }

// 析构迭代器中元素
destroy(start, finish);

// 构造函数填充数据
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);    // 申请内存
    __STL_TRY {
      uninitialized_fill_n(result, n, x);   // 往内存里塞入元素
      return result;
    }
    __STL_UNWIND(data_allocator::deallocate(result, n));
  }

// 创建新的内存空间,并将值拷贝过去,返回最后一个迭代器的位置
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));
  }

// 清空本内存空间,并复制过去值,不创建新的内存空间
copy(last, finish, first); 

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(-1)返回当前平台允许存放的最大字节数,sizeof(T)返回当前模板类型的字节数。相除得当前平台能存储的最大模板类型数
  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); }

  /*构造函数*/
  /*以下构造函数均是通过fill_initialize()对容器进行填充扩容等操作*/
  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;
  }

  /*析构函数*/
  // 两步,析构元素,释放内存空间
  ~vector() { 
    destroy(start, finish); // 析构起始下标到结束下标所有的元素
    deallocate();     // 释放内存空间
  }

  // 赋值运算符
  // 待赋值个数大于当前容量,先把新数据拷贝到新的内存空间,析构并释放原始元素
  // 待赋值个数小于当前容量,不申请新的内存空间,把值复制到当前内存空间中,析构原始元素【不释放内存空间】
  template <class T, class Alloc>
    vector<T, Alloc>& vector<T, Alloc>::operator=(const vector<T, Alloc>& x) {  // 赋值运算符
    if (&x != this) {
        if (x.size() > capacity()) {  // 个数大于当前容量(修改空间大小)
        iterator tmp = allocate_and_copy(x.end() - x.begin(),
                                        x.begin(), x.end()); // 复制过来,删除原空间
        destroy(start, finish);
        deallocate();
        start = tmp;
        end_of_storage = start + (x.end() - x.begin());
        }
        else if (size() >= x.size()) {  // 在容量范围内,但是新的比旧的多
        iterator i = copy(x.begin(), x.end(), begin());   // 直接复制过来
        destroy(i, finish);   // 析构多余元素
        }
        else {  // 新的比旧的少,
        copy(x.begin(), x.begin() + size(), start);
        uninitialized_copy(x.begin() + size(), x.end(), finish);
        }
        finish = start + x.size();
    }
    return *this;
    }
  

  // 预置n个元素空间的大小
  // 判断当前容量是否小于预置容器容量,如果小于,那么扩容。【预置n个大小的内存,小于那么扩容为n【并非2倍】;大于不扩容,也不释放原有内存空间,不错任何操作】
  // 把旧数据赋值到新的容器中
  // 析构原数据,释放内存空间,重置指针位置
  void reserve(size_type n) {   // 预置n个元素的存储空间[扩容到合适大小,不做二倍扩容,不赋值]
  // 如果期望预置容量小于当前最大容量,不做操作
    if (capacity() < n) {   // 如果期望预置容量大于当前最大容量
      const size_type old_size = size();  // 获取当前长度
      iterator tmp = allocate_and_copy(n, start, finish); // 复制n个元素到新的容器中
      destroy(start, finish);   // 析构这些元素
      deallocate();   // 释放所有内存
      start = tmp;    // 重置三个主要指针的位置
      finish = tmp + old_size; 
      end_of_storage = start + n;
    }
  }

  // 返回顶部和底部数据的引用
  reference front() { return *begin(); }  // 返回顺序表顶部
  const_reference front() const { return *begin(); }
  reference back() { return *(end() - 1); }   // 返回顺序表底部
  const_reference back() const { return *(end() - 1); }

  // 添加(尾部添加)
  // 有就直接添加,修改尾部指针;没有就先扩容,再添加,修改尾部指针。
  void push_back(const T& x) {
    if (finish != end_of_storage) { // 没有走到尾部,还有空闲空间
      construct(finish, x);   // 把数据放到vector里,并把finish指针变为指向当前值
      ++finish;   // 指针后移
    }
    else
      insert_aux(end(), x); // 没有走到尾部,没有空闲空间,那么需要先扩容,再添加
  }

  // 交换
  // 两个vector交换,只需要交换他们指针所指向的迭代器下标,所以速度很快。
  void swap(vector<T, Alloc>& x) {  
    __STD::swap(start, x.start);
    __STD::swap(finish, x.finish);
    __STD::swap(end_of_storage, x.end_of_storage);
  }

  // 插入(插入单独元素,在任意位置)
  // 尾部添加,同pushback,判容量,是否扩容,塞入元素,修改指针位置。
  // 中间添加,判容量,是否扩容,前半个塞进新内存,新数据和后半个塞进新内存,修改指针位置。(整个数据都要挪动一次内存位置)
  iterator insert(iterator position, const T& x) {
    size_type n = position - begin();
    if (finish != end_of_storage && position == end()) {   // 如果不越界,且是尾部插入,那么执行插入
      construct(finish, x);
      ++finish;
    }
    else  // 如果中间插入/越界的话,那么需要把整个位置再挪动一次
      insert_aux(position, x);
    return begin() + n;
  }

  /*vector所有的删除,清空之类,都只析构元素,不释放内存空间,改变容器大小*/
  /*vector包括重置在内,所有删除重置操作,都只会析构元素,不会释放已申请的内存空间*/
  /*vector所有和释放内存空间有关的操作,都只会申请新的内存,然后移动元素过去,不会把旧内存的内存空间释放掉*/
  // 删除顶部元素,析构元素,不释放内存空间
  void pop_back() {   // 删除最后一个元素,终止迭代器前移一位,释放掉最后一位的内存
    --finish;
    destroy(finish);
  }

  // 删除单个元素
  // 最后一位直接析构元素【不移动内存】
  // 如果不是最后一位的话,把删除部分之前的元素,内存中全部前移一位【需要移动内存】
  iterator erase(iterator position) {
    if (position + 1 != end())  // 如果不是最后一位的话
    // 把pos后退一位至结束的元素,复制到pos为开始的内存中
    // 把删除位置往后的所有数据,拷贝到删除位置以外的结束位置开始的内存空间中,原finish位置变空
      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;
  }

  // 重置元素大小
  // 如果原始大小大于新的重置大小,那么删除原始元素
  // 如果原始大小大于新的重置大小,那么判断是否扩容,然后把旧数据迁移到新的内存空间,默认数据填充满新的剩余内存空间
  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 clear() { erase(begin(), end()); }   // 删除所有元素,不释放空间

  // 重写==运算符
  template <class T, class Alloc>
inline bool operator==(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {// 判等
// 先比较个数,再比较它们之间的元素是否相等
  return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
}

 // 重写比较运算符
 template <class T, class Alloc>
inline bool operator<(const vector<T, Alloc>& x, const vector<T, Alloc>& y) { // 判大小
// 依次比较大小
  return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值