STL模拟实现—vector

引言:本篇文章主要是模拟实现vector,但不同于stl中vector的成员变量都是迭代器,这个自定义的vector是一个T* 的数据变量和一个int类型的size和int类型的capacity。(有时间再写三个迭代器的版本吧!)

首先来看一下vector的结构 :

start、finish、end_of_storage都是迭代器,也就对应vector类的三个成员变量

 本篇实现的自定义vector类实现了如下功能:

  • 类模板vector的定义:模板类vector拥有构造函数、析构函数、拷贝构造函数、赋值运算符重载,以及其他一些成员函数。
  • 构造函数:默认构造函数创建一个空的向量。带有两个参数的构造函数创建一个具有指定大小和初始值的向量。
  • 析构函数:释放内存并将大小和容量重置为0。
  • 成员函数size()和capacity():分别返回向量的大小和容量。
  • 成员函数push_back():将元素添加到向量的末尾。如果向量已满,则自动扩容。
  • 成员函数reserve():为向量分配指定的容量大小。
  • 重载运算符[]:通过下标访问向量中的元素。
  • 成员函数begin()和end():返回迭代器的起始和结束位置。
  • 成员函数insert()和erase():在指定位置插入或删除元素。
  • 成员函数find():在指定范围内查找元素,并返回迭代器。

 下面是代码:

 my_vector.h

#pragma once
#include <iostream>
#include <assert.h>

using std::cout;  
using std::endl;

template <class T> //模板类声明
class vector{
public:
  vector(); //默认构造函数

  ~vector(); //析构函数

  vector(const vector& v); //拷贝构造函数

  vector& operator=(vector v); //赋值运算符

  typedef T* iterator; //迭代器类型定义

  typedef const T* const_iterator; //常量迭代器类型定义

  vector(size_t n,const T& val); //构造函数,用n个val初始化

  size_t size()const; //返回大小

  size_t capacity()const; //返回容量

  void push_back(const T& val); //尾部插入元素

  void reserve(size_t n); //容量预留

  T& operator[](size_t n); //下标访问运算符

  const T& operator[](size_t n)const; //常量版本下标访问运算符

  iterator begin(); //返回开始迭代器

  iterator end(); //返回结束迭代器

  const_iterator begin()const; //返回常量开始迭代器

  const_iterator end()const; //返回常量结束迭代器

  iterator insert (iterator position, const T& val); //迭代器版本插入

  iterator insert (int position,const T& val); //整数位置版本插入  

  iterator erase (iterator position); //迭代器版本删除

  iterator erase (int position); //整数位置版本删除

  iterator find (iterator _begin,iterator _end,const T& val); //查找元素

private:
  
  T* _data; //内部存储空间指针

  size_t _size; //当前大小 

  size_t _capacity; //当前容量
};

 my_vector.cpp

#include "my_vector.h"
template<class T>
vector<T>::vector()
  :_data(nullptr)
  ,_size(0)
  ,_capacity(0)
{}
template <class T>
vector<T>::~vector(){
  delete [] _data;
  _size = 0;
  _capacity = 0;
}
//构造器—开辟n个val的数组
template<class T>
vector<T>::vector(size_t n,const T& val){
  _data = new T[n];
  for(size_t i = 0; i<n;i++){
    _data[i] = val;
  }
  _size = n;
  _capacity = n;
}

template<class T>
size_t vector<T>::size()const{
  return _size;
}

template<class T>
size_t vector<T>::capacity()const{
  return _capacity;
}

template <class T>
void vector<T>::reserve(size_t n){
    if(n==0)return;
    T* tmp = new T[n];
    for(size_t i =0;i<_size;i++){//深拷贝
      tmp[i] = _data[i];
    }
    delete []_data;
    _data = tmp;
    _capacity = n;
}

template<class T>
void vector<T>::push_back(const T& val){
  if(_size == _capacity){//扩容
    _capacity = _capacity == 0?2:(_capacity*1.5);
    reserve(_capacity);
    }
    _data[_size] = val;
    _size++;
  }

template <class T>
T& vector<T>::operator[](size_t n){
    assert(n<_size);//断言n要小于size
    return _data[n];
}
template<class T>
const T& vector<T>::operator[](size_t n)const{
  assert(n<_size);
  return _data[n];
} 
template <class T>
typename vector<T>::iterator vector<T>::begin(){
  //定义时需要加上 typename 告诉编译器这是一个类型,因为这个类型是我们typedef出来的 
  return _data;
}
template <class T>
typename vector<T>::iterator vector<T>::end(){
    return _data+_size;
}
template <class T>
typename vector<T>::const_iterator vector<T>::end()const{
    return _data+_size;
}

template <class T>
typename vector<T>::const_iterator vector<T>::begin()const{
    return _data+_size;
}
template <class T>
vector<T>::vector(const vector& v){
  if(this == &v)return;//如果拷贝构造自己返回
  _data = new T[v._size];
  for(int i = 0;i<v._size;i++){
    _data[i]=v[i];
  }
  _capacity = v._size;
  _size = v._size;
}
template <class T>
vector<T>& vector<T>::operator=(vector v){
//赋值现代写法,利用传过来的值,拿临时变量v拷贝构造
//再交换他们的值,这个临时变量又会出作用域销毁
  _data = v._data;
  v._data = nullptr;
  _size = v._size;
  _capacity = v._capacity;
  return *this;
}
template <class T>
typename vector<T>::iterator vector<T>::insert (vector<T>::iterator position, const T& val){
  assert(position<=end());
  int pos = position -begin();
  if(_capacity == _size){//需要扩容
    _capacity = _capacity==0?2:(_capacity*1.5);
    reserve(_capacity);
  }
  position = begin()+pos;
  for(vector<T>::iterator it = end()-1;it>=position;it--){
     *(it+1)=*it;
  }
  *position = val;
  _size++;
  return position;
}
template <class T>
typename vector <T>::iterator vector<T>::insert(int position,const T& val){
  return insert(begin()+position,val);
}
template <class T>
typename vector<T>::iterator vector<T>::erase(vector<T>::iterator position){
  assert(position >= begin() && position < end());//迭代器不能大于或等于end()
  for(vector<T>::iterator it = position+1;it<=end();it++){
    *(it-1)=*it;
  }
  _size--;
  return position;
}
template <class T>
typename vector<T>::iterator vector<T>::erase(int position){
  return erase(begin()+position);
}
template <class T>
typename vector<T>::iterator vector<T>::find(vector<T>::iterator _begin,vector<T>::iterator _end,const T& val){
 if(_begin>=end() || _end<begin()) return nullptr;
  if(_begin<begin()) _begin=begin();//条件限制一下
  if(_end>=end()) _end = end()-1;
  for(vector<T>::iterator it = _begin;it<=_end;it++){
    if(*it == val) return it;//找到返回迭代器
  }
  return nullptr;
}

 main.cpp

#include "my_vector.cpp"
void test01(){
vector<int> v1;
  v1.push_back(1);
  v1.push_back(2);
  v1.push_back(5);
  v1.push_back(3);
  v1.push_back(100);
  cout<<v1[1]<<endl;
  for(auto& e : v1){
    cout<<e<<' ';
  }
  cout<<endl;
  cout<<v1.capacity()<<endl;
  vector<int> v2;
  v2 = v1;
  v2.insert(v2.begin()+2,1230);
  for(auto& e:v2){
    cout<<e<<' ';
  }
  cout<<endl;
  v2.erase(v2.end()-1);
  for(auto& e:v2){
    cout<<e<<' ';
  }
  cout<<endl;
  cout<<*(v2.find(v2.begin(),v2.end(),5))<<endl;
}
int main(){
  test01();
}

注意事项:

 1. mian.cpp中,需要包含的文件是my_vector.cpp,不能像一般那样包含my_vector.h

因为如果模板的声明和定义分别单独的放在.h和.cpp文件中,当要实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的声明若在main()函数中包含.h文件,则编译器无法知道模板的确切定义,所以要在main()中包含.cpp文件,.cpp文件中又会包含.h文件,这样一来通过在main函数中包含.cpp文件就会将类的定义和声明都包含进来,编译器自然能找到模板的确切定义。

2. 深浅拷贝问题

 在上面的代码中,每次进行拷贝和移动时,都是经过for循环,一个个去拷到新数组中去的,并没有使用memset等函数,因为memset是以一个字节一个字节进行拷贝的,如果此时vector里面存放的是自定义类型的数据,就会出错。

3. 迭代器失效问题 

my_vector.cpp中,insert函数如果不注意就会发生迭代器失效

如图:传进来的迭代器,如果进行扩容了,那么这个迭代器也就失效了,因为其指向的是旧空间的,而旧空间已经释放。 

所以,需要提前记录下迭代器与begin()的距离,再到扩容后重新更新这个迭代器。

 总之:写模板类还是有点挑战的,需要多加练习!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值